From 70968e59e8cd5da355e063bd183047b08aabb14c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20Sch=C3=B6berl?= Date: Fri, 28 Feb 2020 20:54:22 +0100 Subject: [PATCH 001/384] optimal order reading of names --- libsrc/occ/occgeom.cpp | 97 +++++++++++++++++++++++++++++++----------- libsrc/occ/occgeom.hpp | 2 +- 2 files changed, 72 insertions(+), 27 deletions(-) diff --git a/libsrc/occ/occgeom.cpp b/libsrc/occ/occgeom.cpp index 20c8e303..20e59d90 100644 --- a/libsrc/occ/occgeom.cpp +++ b/libsrc/occ/occgeom.cpp @@ -22,7 +22,8 @@ #include "XSControl_TransferReader.hxx" #include "StepRepr_RepresentationItem.hxx" #include "StepBasic_ProductDefinitionRelationship.hxx" - +#include "Transfer_TransientProcess.hxx" +#include "TransferBRep.hxx" #ifndef _Standard_Version_HeaderFile #include #endif @@ -1379,45 +1380,89 @@ namespace netgen PrintContents (occgeo); string name; TopExp_Explorer exp0,exp1; + + + + std::map shape_names; + { + static Timer t("file shape_names"); RegionTimer r(t); + // code inspired from + // https://www.opencascade.com/content/reading-step-entity-id-slow + const Handle(XSControl_WorkSession) workSession = reader.Reader().WS(); + const Handle(Interface_InterfaceModel) model = workSession->Model(); + const Handle(XSControl_TransferReader) transferReader = workSession->TransferReader(); + Handle(Transfer_TransientProcess) transProc = transferReader->TransientProcess(); + + Standard_Integer nb = model->NbEntities(); + for (Standard_Integer i = 1; i < nb; i++) + { + Handle(Standard_Transient) entity = model->Value(i); + + // if (!entity->DynamicType()->SubType("StepShape_OpenShell")) continue; + + Handle(StepRepr_RepresentationItem) SRRI = + Handle(StepRepr_RepresentationItem)::DownCast(entity); + + if (SRRI.IsNull()) { + // cout << "no StepRepr_RepresentationItem found in " << entity->DynamicType()->Name(); + continue; + } + Handle(TCollection_HAsciiString) hName = SRRI->Name(); + string shapeName = hName->ToCString(); + + // cout << "STEP " << i << " " << entity->DynamicType()->Name() << ", shapename = " << shapeName; + Handle(Transfer_Binder) binder; + if (!transProc->IsBound(SRRI)) { + // cout << "found unbound entity " << shapeName; + continue; + } + binder = transProc->Find(SRRI); + TopoDS_Shape shape = TransferBRep::ShapeResult(binder); + // if (!shape.IsNull()) + shape_names[shape.TShape()] = shapeName; + /* + if (!shape.IsNull()) + cout << " shapetype = " << shape.ShapeType() << endl; + else + cout << "is-Null" << endl; + */ + } + // for (auto pair : shape_names) + // cout << "name = " << pair.second << endl; + } + timer_getnames.Start(); for (exp0.Init(occgeo->shape, TopAbs_SOLID); exp0.More(); exp0.Next()) { TopoDS_Solid solid = TopoDS::Solid(exp0.Current()); - name = STEP_GetEntityName(solid,&reader); + // name = STEP_GetEntityName(solid,&reader); + // cout << "solidname = " << name << ", mapname = " << shape_names[solid.TShape()] << endl; + name = shape_names[solid.TShape()]; if (name == "") - name = string("domain_") + ToString(occgeo->snames.Size()); + name = string("domain_") + ToString(occgeo->snames.Size()); occgeo->snames.Append(name); } + for (exp0.Init(occgeo->shape, TopAbs_FACE); exp0.More(); exp0.Next()) { TopoDS_Face face = TopoDS::Face(exp0.Current()); - name = STEP_GetEntityName(face,&reader); + // name = STEP_GetEntityName(face,&reader); + // cout << "getname = " << name << ", mapname = " << shape_names[face.TShape()] << endl; + name = shape_names[face.TShape()]; if (name == "") - name = string("bc_") + ToString(occgeo->fnames.Size()); + name = string("bc_") + ToString(occgeo->fnames.Size()); occgeo->fnames.Append(name); -// for (exp1.Init(face, TopAbs_EDGE); exp1.More(); exp1.Next()) -// { -// TopoDS_Edge edge = TopoDS::Edge(exp1.Current()); -// name = STEP_GetEntityName(edge,&reader); -// occgeo->enames.Append(name); -// } + for (exp1.Init(face, TopAbs_EDGE); exp1.More(); exp1.Next()) + { + TopoDS_Edge edge = TopoDS::Edge(exp1.Current()); + // name = STEP_GetEntityName(edge,&reader); + // cout << "getname = " << name << ", mapname = " << shape_names[edge.TShape()] << endl; + name = shape_names[edge.TShape()]; + occgeo->enames.Append(name); + } } - timer_getnames.Stop(); - // Gerhard BEGIN -// cout << "Solid Names: "<snames.Size();i++) -// cout << occgeo->snames[i] << endl; -// cout << " " <fnames.Size();i++) -// cout << occgeo->fnames[i] << endl; -// cout << " " <enames.Size();i++) -// cout << occgeo->enames[i] << endl; -// cout << " " < fsingular, esingular, vsingular; Box<3> boundingbox; - NgArray fnames, /*enames,*/ snames; + NgArray fnames, enames, snames; // Philippose - 29/01/2009 // OpenCascade XDE Support // XCAF Handle to make the face colours available to the rest of From c6c91bb34875f2a17de7e3c3a8282ab9234310d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20Sch=C3=B6berl?= Date: Sat, 29 Feb 2020 13:56:43 +0100 Subject: [PATCH 002/384] set edgenames in mesh --- libsrc/occ/occgenmesh.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libsrc/occ/occgenmesh.cpp b/libsrc/occ/occgenmesh.cpp index be645a14..38902710 100644 --- a/libsrc/occ/occgenmesh.cpp +++ b/libsrc/occ/occgenmesh.cpp @@ -515,6 +515,9 @@ namespace netgen if (!exists) pnums[i] = mesh.AddPoint (mp[i-1]); } + if(geom.enames.Size() && geom.enames[curr-1] != "") + mesh.SetCD2Name(geomedgenr, geom.enames[curr-1]); + (*testout) << "NP = " << mesh.GetNP() << endl; //(*testout) << pnums[pnums.Size()-1] << endl; From 63e414ff0df161f1dffb39e7c94cb9248807af73 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Mon, 2 Mar 2020 17:03:50 +0100 Subject: [PATCH 003/384] Add missing header in occgeom.cpp --- libsrc/occ/occgeom.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libsrc/occ/occgeom.cpp b/libsrc/occ/occgeom.cpp index 20e59d90..037022f9 100644 --- a/libsrc/occ/occgeom.cpp +++ b/libsrc/occ/occgeom.cpp @@ -17,6 +17,7 @@ #include "ShapeFix_FixSmallFace.hxx" #include "Partition_Spliter.hxx" #include "BRepAlgoAPI_Fuse.hxx" +#include "Interface_InterfaceModel.hxx" #include "XSControl_WorkSession.hxx" #include "XSControl_TransferReader.hxx" From 0bcee4d6b0f5d3660a8c0a42c7ddf4c432a636ff Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Mon, 2 Mar 2020 17:04:11 +0100 Subject: [PATCH 004/384] Fix FindOpenCasCade.cmake --- cmake/cmake_modules/FindOpenCasCade.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/cmake_modules/FindOpenCasCade.cmake b/cmake/cmake_modules/FindOpenCasCade.cmake index 053cd680..e82f8dac 100644 --- a/cmake/cmake_modules/FindOpenCasCade.cmake +++ b/cmake/cmake_modules/FindOpenCasCade.cmake @@ -25,7 +25,7 @@ else(WIN32) ) endif(WIN32) -if(OCC_LIBRARY) +if(OCC_LIBRARY AND NOT OCC_LIBRARY_DIR) get_filename_component(OCC_LIBRARY_DIR ${OCC_LIBRARY} PATH) endif(OCC_LIBRARY) @@ -89,7 +89,7 @@ if(OCC_VERSION_STRING VERSION_GREATER_EQUAL "7.3.0") endif() foreach( libname ${OCC_LIBRARY_NAMES} ) - find_library( ${libname} ${libname} ${OCC_LIBRARY_DIR} ) + find_library( ${libname} ${libname} ${OCC_LIBRARY_DIR} NO_DEFAULT_PATH) set(OCC_LIBRARIES ${OCC_LIBRARIES} ${${libname}}) endforeach() From d994c589d319033dd0d4061480bd06d0f8e247b5 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Mon, 2 Mar 2020 17:29:35 +0100 Subject: [PATCH 005/384] Remove onetcl.cpp from netgen exe (is already in meshing lib) --- ng/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ng/CMakeLists.txt b/ng/CMakeLists.txt index 67f42ea0..82d8ea91 100644 --- a/ng/CMakeLists.txt +++ b/ng/CMakeLists.txt @@ -22,7 +22,7 @@ if(USE_GUI) ../libsrc/occ/occpkg.cpp ../libsrc/occ/vsocc.cpp ) - add_executable(netgen ngappinit.cpp onetcl.cpp) + add_executable(netgen ngappinit.cpp) 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} ) From 1d652d8206f8e3840bea7a829e7ca491719a6dae Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Mon, 2 Mar 2020 16:56:46 +0000 Subject: [PATCH 006/384] DLL_HEADER in onetcl --- ng/ngappinit.cpp | 2 +- ng/onetcl.cpp | 3 ++- ng/onetcl.py | 3 ++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/ng/ngappinit.cpp b/ng/ngappinit.cpp index 7480ef5a..d277fa82 100644 --- a/ng/ngappinit.cpp +++ b/ng/ngappinit.cpp @@ -206,7 +206,7 @@ int main(int argc, char ** argv) cout << "using internal Tcl-script" << endl; // connect to one string - extern const char * ngscript[]; + DLL_HEADER const char * ngscript[]; const char ** hcp = ngscript; int len = 0; while (*hcp) diff --git a/ng/onetcl.cpp b/ng/onetcl.cpp index 8e3513c5..a0a31da4 100644 --- a/ng/onetcl.cpp +++ b/ng/onetcl.cpp @@ -1,4 +1,5 @@ -const char * ngscript[] = {"" +#include +DLL_HEADER const char * ngscript[] = {"" ,"catch {lappend auto_path $env(NETGENDIR) }\n" ,"catch {lappend auto_path $env(NETGENDIR)/../lib }\n" ,"if {[catch {Ng_GetCommandLineParameter batchmode} result ]} {\n" diff --git a/ng/onetcl.py b/ng/onetcl.py index dfdedbd8..d8559855 100644 --- a/ng/onetcl.py +++ b/ng/onetcl.py @@ -19,7 +19,8 @@ for f in fnames: # write a cpp file containing the result of ng.tcl onetclcpp = open("onetcl.cpp",'w') -onetclcpp.write('const char * ngscript[] = {""'+'\n'); +onetclcpp.write('#include \n'); +onetclcpp.write('DLL_HEADER const char * ngscript[] = {""'+'\n'); # make sure to remove comments (and if lines with comments end with '\' also the next line(s) ) skip_next = False # flag to indicate that the next line should be removed From bd600f48ac17831c7a867c6014e9acba51de01f4 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Mon, 2 Mar 2020 18:03:54 +0100 Subject: [PATCH 007/384] Fix declaration of ngscript --- ng/ngappinit.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ng/ngappinit.cpp b/ng/ngappinit.cpp index d277fa82..9e0825a3 100644 --- a/ng/ngappinit.cpp +++ b/ng/ngappinit.cpp @@ -206,7 +206,7 @@ int main(int argc, char ** argv) cout << "using internal Tcl-script" << endl; // connect to one string - DLL_HEADER const char * ngscript[]; + DLL_HEADER extern const char * ngscript[]; const char ** hcp = ngscript; int len = 0; while (*hcp) From 1d62ca31ac6d54505b202b23dc68866c76374184 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Tue, 3 Mar 2020 11:10:09 +0000 Subject: [PATCH 008/384] DLL_HEADER for BlockAllocator (used in BoxTree) --- libsrc/general/optmem.hpp | 34 ++++------------------------------ 1 file changed, 4 insertions(+), 30 deletions(-) diff --git a/libsrc/general/optmem.hpp b/libsrc/general/optmem.hpp index 99ffb67d..b2be31d3 100644 --- a/libsrc/general/optmem.hpp +++ b/libsrc/general/optmem.hpp @@ -26,39 +26,13 @@ private: mutex block_allocator_mutex; public: /// - BlockAllocator (unsigned asize, unsigned ablocks = 100); + DLL_HEADER BlockAllocator (unsigned asize, unsigned ablocks = 100); /// - ~BlockAllocator (); + DLL_HEADER ~BlockAllocator (); /// - - void * Alloc (); - /* - { - if (!freelist) - Alloc2(); - - void * p = freelist; - // freelist = *(void**)freelist; - freelist = *static_cast (freelist); - - return p; - } - */ - - + DLL_HEADER void * Alloc (); /// - void Free (void * p); - /* - { - if (!bablocks.Size()) return; - *(void**)p = freelist; - freelist = p; - } - */ - - -private: - // void Alloc2 (); + DLL_HEADER void Free (void * p); }; } From 672ce3f3f2089e11904f347185b328a24aca7a43 Mon Sep 17 00:00:00 2001 From: Lukas Date: Fri, 6 Mar 2020 10:17:09 +0100 Subject: [PATCH 009/384] Interface can now give curve order of mesh --- libsrc/include/nginterface_v2.hpp | 1 + libsrc/interface/nginterface_v2.cpp | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/libsrc/include/nginterface_v2.hpp b/libsrc/include/nginterface_v2.hpp index 081422d3..417bdf72 100644 --- a/libsrc/include/nginterface_v2.hpp +++ b/libsrc/include/nginterface_v2.hpp @@ -343,6 +343,7 @@ namespace netgen void SetRefinementFlag (size_t elnr, bool flag); void Curve (int order); + int GetCurveOrder (); void Refine (NG_REFINEMENT_TYPE reftype, void (*taskmanager)(function) = &DummyTaskManager2, diff --git a/libsrc/interface/nginterface_v2.cpp b/libsrc/interface/nginterface_v2.cpp index a961e999..f40823e3 100644 --- a/libsrc/interface/nginterface_v2.cpp +++ b/libsrc/interface/nginterface_v2.cpp @@ -1134,6 +1134,10 @@ namespace netgen mesh->BuildCurvedElements(order); } + int Ngx_Mesh :: GetCurveOrder () + { + return mesh->GetCurvedElements().GetOrder(); + } template <> DLL_HEADER void Ngx_Mesh :: SetRefinementFlag<2> (size_t elnr, bool flag) From db5ad09b790f4522c887f437dc01d9e5e1e1f734 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Wed, 11 Mar 2020 11:48:05 +0100 Subject: [PATCH 010/384] Initial CGNS format read support --- CMakeLists.txt | 10 + cmake/SuperBuild.cmake | 1 + libsrc/interface/CMakeLists.txt | 4 +- libsrc/interface/readuser.cpp | 7 + libsrc/interface/rw_cgns.cpp | 466 ++++++++++++++++++++++++++++++++ libsrc/interface/writeuser.hpp | 9 + libsrc/meshing/python_mesh.cpp | 1 + ng/menustat.tcl | 1 + ng/onetcl.cpp | 1 + tests/build_debug.sh | 8 +- tests/dockerfile | 2 +- 11 files changed, 506 insertions(+), 4 deletions(-) create mode 100644 libsrc/interface/rw_cgns.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 009660aa..8f11ccca 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,6 +17,7 @@ option( USE_MPI "enable mpi parallelization" OFF ) option( USE_OCC "(not supported) compile with OpenCascade geometry kernel" OFF) option( USE_JPEG "enable snapshots using library libjpeg" OFF ) option( USE_MPEG "enable video recording with FFmpeg, uses libavcodec" OFF ) +option( USE_CGNS "enable CGNS file read/write support" OFF ) option( INTEL_MIC "cross compile for intel xeon phi") option( INSTALL_PROFILES "install environment variable settings to /etc/profile.d" OFF ) option( USE_CCACHE "use ccache") @@ -388,6 +389,15 @@ if(ENABLE_CPP_CORE_GUIDELINES_CHECK) endif() endif(ENABLE_CPP_CORE_GUIDELINES_CHECK) +add_library(netgen_cgns INTERFACE) +if(USE_CGNS) + find_library( CGNS_LIBRARY cgns ) + find_path( CGNS_INCLUDE_DIR cgnslib.h ) + target_compile_definitions(netgen_cgns INTERFACE NG_CGNS) + target_include_directories(netgen_cgns INTERFACE ${CGNS_INCLUDE_DIR}) + target_link_libraries(netgen_cgns INTERFACE ${CGNS_LIBRARY}) +endif(USE_CGNS) + add_subdirectory(libsrc) add_subdirectory(ng) add_subdirectory(tutorials) diff --git a/cmake/SuperBuild.cmake b/cmake/SuperBuild.cmake index a04e4164..83dfe269 100644 --- a/cmake/SuperBuild.cmake +++ b/cmake/SuperBuild.cmake @@ -128,6 +128,7 @@ set_vars( NETGEN_CMAKE_ARGS USE_OCC USE_MPEG USE_JPEG + USE_CGNS USE_INTERNAL_TCL INSTALL_PROFILES INTEL_MIC diff --git a/libsrc/interface/CMakeLists.txt b/libsrc/interface/CMakeLists.txt index bc1bc2f3..47661a0c 100644 --- a/libsrc/interface/CMakeLists.txt +++ b/libsrc/interface/CMakeLists.txt @@ -4,10 +4,10 @@ add_library(interface ${NG_LIB_TYPE} read_fnf_mesh.cpp readtetmesh.cpp readuser.cpp writeabaqus.cpp writediffpack.cpp writedolfin.cpp writeelmer.cpp writefeap.cpp writefluent.cpp writegmsh.cpp writejcm.cpp writepermas.cpp writetecplot.cpp writetet.cpp writetochnog.cpp writeuser.cpp - wuchemnitz.cpp writegmsh2.cpp writeOpenFOAM15x.cpp + wuchemnitz.cpp writegmsh2.cpp writeOpenFOAM15x.cpp rw_cgns.cpp ) -target_link_libraries(interface mesh csg geom2d stl visual) +target_link_libraries(interface PUBLIC mesh csg geom2d stl visual PRIVATE netgen_cgns) if(NOT WIN32) install( TARGETS interface ${NG_INSTALL_DIR}) diff --git a/libsrc/interface/readuser.cpp b/libsrc/interface/readuser.cpp index 472592ac..d3d50cf2 100644 --- a/libsrc/interface/readuser.cpp +++ b/libsrc/interface/readuser.cpp @@ -649,6 +649,13 @@ namespace netgen ReadFNFFormat (mesh, filename); } + // .cgns file - CFD General Notation System + if ( (strlen (filename) > 5) && + strcmp (&filename[strlen (filename)-5], ".cgns") == 0 ) + { + ReadCGNSMesh (mesh, filename); + } + if ( ( (strlen (filename) > 4) && strcmp (&filename[strlen (filename)-4], ".stl") == 0 ) || ( (strlen (filename) > 5) && strcmp (&filename[strlen (filename)-5], ".stlb") == 0 ) ) { diff --git a/libsrc/interface/rw_cgns.cpp b/libsrc/interface/rw_cgns.cpp new file mode 100644 index 00000000..7de2aefb --- /dev/null +++ b/libsrc/interface/rw_cgns.cpp @@ -0,0 +1,466 @@ +#include +#include "writeuser.hpp" + +#ifdef NG_CGNS +#include + +#include + +namespace netgen::cg +{ + int getDim(ElementType_t type) + { + switch(type) + { + case BAR_2: + case BAR_3: + return 1; + case TRI_3: + case TRI_6: + case QUAD_4: + case QUAD_8: + return 2; + case TETRA_4: + case TETRA_10: + case PYRA_5: + case PYRA_13: + case HEXA_8: + case HEXA_20: + case PENTA_6: + case PENTA_15: + return 3; + default: + throw Exception("Read CGNS: unknown element type " + string(ElementTypeName[type])); + } + } + + Segment ReadCGNSElement1D( ElementType_t type, FlatArray verts, int vert_offset=0 ) + { + int np; + cg_npe(type, &np); + + Segment s; + for (auto i : Range(np)) + s[i] = vert_offset+verts[i]; + return s; + } + + Element2d ReadCGNSElement2D( ElementType_t type, FlatArray verts, int vert_offset=0 ) + { + static constexpr int map_tri3[] = {0,2,1}; + static constexpr int map_tri6[] = {0,2,1,3,5,4}; // untested + static constexpr int map_quad4[] = {0,3,2,1}; + static constexpr int map_quad8[] = {0,3,2,1,4,7,6,5}; // untested + + const int * map = nullptr; + switch(type) + { + case TRI_3: + map = map_tri3; + break; + case QUAD_4: + map = map_quad4; + break; + case TRI_6: + map = map_tri6; + break; + case QUAD_8: + map = map_quad8; + break; + default: + throw Exception("Read CGNS: unknown element type " + string(ElementTypeName[type])); + } + + int np; + cg_npe(type, &np); + + Element2d el(np); + for (auto i : Range(np)) + el[i] = vert_offset+verts[map[i]]; + return el; + } + + Element ReadCGNSElement3D( ElementType_t type, FlatArray verts, int vert_offset=0 ) + { + static constexpr int map_tet4[] = {0,2,1,3}; + static constexpr int map_prism6[] = {0,2,1,3,5,4}; + static constexpr int map_pyra5[] = {0,3,2,1,4}; + static constexpr int map_hexa8[] = {0,3,2,1,4,7,6,5}; + int np; + cg_npe(type, &np); + + const int * map = nullptr; + switch(type) + { + case TETRA_4: + map = map_tet4; break; + case PYRA_5: + map = map_pyra5; break; + case PENTA_6: + map = map_prism6; break; + case HEXA_8: + map = map_hexa8; break; + // TODO: Second order elements + case TETRA_10: + case PYRA_13: + case HEXA_20: + case PENTA_15: + default: + throw Exception("Read CGNS: unknown element type " + string(ElementTypeName[type])); + } + + Element el(np); + for (auto i : Range(np)) + el[i] = vert_offset+verts[map[i]]; + return el; + } + + // maps cgns node type to ngsolve node type + // enum NODE_TYPE { NT_VERTEX = 0, NT_EDGE = 1, NT_FACE = 2, NT_CELL = 3, NT_ELEMENT = 4, NT_FACET = 5 }; + int getNodeType( GridLocation_t location ) + { + switch(location) + { + case Vertex: + return 0; + case CellCenter: + return 3; + case FaceCenter: + return 2; + case EdgeCenter: + return 1; + default: + throw Exception("Read CGNS: unknown grid location " + string(GridLocationName[location])); + } + } + + + struct Solution + { + int fn, base, zone, solution; + string name; + GridLocation_t location; // solution is defined on either cells, faces, edges or vertices + PointSetType_t point_type; + cgsize_t n_points; + + Array field_names; + Array field_datatypes; + + Solution() = default; + + Solution(int fn_, int base_, int zone_, int solution_) + : fn(fn_), base(base_), zone(zone_), solution(solution_) + { + char solname[100]; + cg_sol_info(fn, base, zone, solution, solname, &location); + name = solname; + cg_sol_ptset_info(fn, base, zone, solution, &point_type, &n_points); + + int n_fields = 0; + cg_nfields(fn, base, zone, solution, &n_fields); + + field_names.SetSize(n_fields); + field_datatypes.SetSize(n_fields); + for(auto fi : Range(n_fields)) + { + char buf[100]; + cg_field_info(fn, base, zone, solution, fi+1, &field_datatypes[fi], buf); + field_names[fi] = buf; + } + } + }; + + struct Zone + { + ZoneType_t zone_type; + int fn, base, zone; + int nv, ne, first_vertex, first_mat, first_bc; + Array materials; + Array boundaries; + string name; + cgsize_t size[3]; + + Array solutions; + + Zone(int fn_, int base_, int zone_) + : fn(fn_), base(base_), zone(zone_) + { + cg_zone_type(fn, base, zone, &zone_type); + char zone_name[100]; + cg_zone_read(fn,base,zone, zone_name, size); + nv = size[0]; + + int n_solutions; + cg_nsols(fn, base, zone, &n_solutions); + + solutions.SetSize(n_solutions); + for(auto si : Range(n_solutions)) + solutions[si] = Solution{fn, base, zone, si+1}; + } + + void ReadSolutions( std::vector & sol_names, std::vector> & sol_values, std::vector & sol_locations ) + { + static Timer tall("CGNS::ReadSolutions"); RegionTimer rtall(tall); + for (auto & sol : solutions) + { + for (auto fi : Range(sol.field_names.Size())) + { + cgsize_t size = sol.n_points; + if(size==0) + { + switch(sol.location) + { + case Vertex: + size = nv; + break; + case CellCenter: + size = ne; + break; + case FaceCenter: + case IFaceCenter: + case JFaceCenter: + case KFaceCenter: + case EdgeCenter: + default: + throw Exception("Read CGNS: unknown grid location " + string(GridLocationName[sol.location])); + } + } + + size = size==0 ? nv : size; + auto values = Array(size); + + cgsize_t imin = 1UL; + cg_field_read(fn, base, zone, sol.solution, sol.field_names[fi].c_str(), RealDouble, &imin, &size, &values[0]); + sol_names.push_back(sol.field_names[fi]); + sol_values.emplace_back(std::move(values)); + sol_locations.push_back(sol.location); + } + } + } + + void ReadMesh( Mesh & mesh ) + { + static Timer tall("CGNS::ReadMesh-Zone"); RegionTimer rtall(tall); + static Timer tsection("CGNS::ReadMesh-Section"); + first_vertex = mesh.GetNP(); + first_mat = mesh.GetRegionNamesCD(0).Size(); + first_bc = mesh.GetRegionNamesCD(1).Size(); + ne = 0; + + Array x(nv), y(nv), z(nv); + cgsize_t imin=1; + cg_coord_read(fn,base,zone, "CoordinateX", RealSingle, &imin, &nv, &x[0]); + cg_coord_read(fn,base,zone, "CoordinateY", RealSingle, &imin, &nv, &y[0]); + cg_coord_read(fn,base,zone, "CoordinateZ", RealSingle, &imin, &nv, &z[0]); + + for(auto i : Range(nv)) + mesh.AddPoint( {x[i], y[i], z[i]} ); + + int nsections; + cg_nsections(fn, base, zone, &nsections); + + int bc = first_bc; + int material = first_mat; + for (auto section : Range(1,nsections+1)) + { + RegionTimer rtsection(tsection); + char name[100]; + ElementType_t type; + cgsize_t start, end; + int nbndry, parent_flag; + + cg_section_read(fn, base, zone, section, name, &type, &start, &end, &nbndry, &parent_flag); + PrintMessage(4, "Read section ", section, " with name ", name, " and element type ", cg_ElementTypeName(type)); + + string ngname{name}; + + for (char & c : ngname) + if(c==' ') + c = '_'; + + + if(type==MIXED) + { + bc++; + material++; + mesh.AddFaceDescriptor(FaceDescriptor(bc, 1, 0, 1)); + mesh.SetBCName(bc-1, ngname); + mesh.SetMaterial(material, ngname); + + cgsize_t nv; + cg_ElementDataSize(fn, base, zone, section, &nv); + + Array vertices(nv); + cg_poly_elements_read(fn, base, zone, section, &vertices[0], nullptr, nullptr); + + size_t vi = 0; + while(vi(vertices[vi++]); + int dim = getDim(type); + + if(dim==1) + { + auto el = ReadCGNSElement1D(type, vertices.Range(vi, vertices.Size()), first_vertex); + mesh.AddSegment(el); + vi += el.GetNP(); + } + + if(dim==2) + { + auto el = ReadCGNSElement2D(type, vertices.Range(vi, vertices.Size()), first_vertex); + el.SetIndex(bc); + mesh.AddSurfaceElement(el); + vi += el.GetNP(); + } + + if(dim==3) + { + auto el = ReadCGNSElement3D(type, vertices.Range(vi, vertices.Size()), first_vertex); + el.SetIndex(material); + mesh.AddVolumeElement(el); + vi += el.GetNP(); + ne++; + } + } + } + else + { + int dim = getDim(type); + + cgsize_t nv; + cg_ElementDataSize(fn, base, zone, section, &nv); + int np=0; + cg_npe(type, &np); + + Array vertices(nv); + cg_elements_read(fn, base, zone, section, &vertices[0], nullptr); + int ne_section = nv/np; + + if(dim==1) + { + for(auto i : Range(ne_section)) + { + auto el = ReadCGNSElement1D(type, vertices.Range(np*i, np*(i+1)), first_vertex); + mesh.AddSegment(el); + } + } + + if(dim==2) + { + bc++; + mesh.AddFaceDescriptor(FaceDescriptor(bc, 1, 0, 1)); + for(auto i : Range(ne_section)) + { + auto el = ReadCGNSElement2D(type, vertices.Range(np*i, np*(i+1)), first_vertex); + el.SetIndex(bc); + mesh.AddSurfaceElement(el); + } + mesh.SetBCName(bc-1, ngname); + } + + if(dim==3) + { + material++; + for(auto i : Range(ne_section)) + { + auto el = ReadCGNSElement3D(type, vertices.Range(np*i, np*(i+1)), first_vertex); + el.SetIndex(material); + mesh.AddVolumeElement(el); + } + mesh.SetMaterial(material, ngname); + ne += ne_section; + } + } + } + } + }; +} + +namespace netgen +{ + void ReadCGNSMesh (Mesh & mesh, const string & filename) + { + static Timer tall("CGNS::ReadMesh"); RegionTimer rtall(tall); + int fn; + cg_open(filename.c_str(),CG_MODE_READ,&fn); + + int base = 1; + int nzones; + cg_nzones(fn, base, &nzones); + + int bc = 0; + int material = 0; + + for (auto zi : Range(1, nzones+1)) + { + ZoneType_t zone_type; + cg_zone_type(fn, base, zi, &zone_type); + if(zone_type != Unstructured ) + { + PrintMessage(2, "skipping zone with type ", cg_ZoneTypeName(zone_type) ); + continue; + } + cg::Zone zone(fn, base, zi); + zone.ReadMesh( mesh ); + } + } + + // Reads mesh and solutions of .csns file + tuple, vector, vector>, vector> ReadCGNSFile(string filename, int base) + { + static Timer tall("CGNS::ReadFile"); RegionTimer rtall(tall); + int fn; + cg_open(filename.c_str(),CG_MODE_READ,&fn); + + int nbases; + cg_nbases(fn, &nbases); + + int nzones; + cg_nzones(fn, base, &nzones); + + auto mesh = make_shared(); + + int bc = 0; + int material = 0; + + + std::vector names; + std::vector> values; + std::vector locations; + + for (auto zi : Range(1, nzones+1)) + { + ZoneType_t zone_type; + cg_zone_type(fn, base, zi, &zone_type); + if(zone_type != Unstructured ) + { + clog << "skipping zone with type " << cg_ZoneTypeName(zone_type) << endl; + continue; + } + cg::Zone zone(fn, base, zi); + zone.ReadMesh( *mesh ); + zone.ReadSolutions( names, values, locations ); + } + + cg_close(fn); + return std::make_tuple(mesh, names, values, locations); + } +} + +#else // NG_CGNS + +namespace netgen +{ + void ReadCGNSMesh (Mesh & mesh, const string & filename) + { + PrintMessage(1, "Could not import CGNS mesh: Netgen was built without CGNS support"); + } + + tuple, vector, vector>, vector> ReadCGNSFile(string filename, int base) + { + throw Exception("Netgen was built without CGNS support"); + } +} + +#endif // NG_CGNS diff --git a/libsrc/interface/writeuser.hpp b/libsrc/interface/writeuser.hpp index 3e98c433..8c58ea5f 100644 --- a/libsrc/interface/writeuser.hpp +++ b/libsrc/interface/writeuser.hpp @@ -150,6 +150,15 @@ extern void ReadFNFFormat (Mesh & mesh, +extern void DLL_HEADER ReadCGNSMesh (Mesh & mesh, + const string & filename); + +// Read Mesh and solutions from CGNS file +extern tuple, vector, vector>, vector> +DLL_HEADER ReadCGNSFile(string filename, int base); + + + void WriteDolfinFormat (const Mesh & mesh, const string & filename); diff --git a/libsrc/meshing/python_mesh.cpp b/libsrc/meshing/python_mesh.cpp index 45adc9fd..23cb5d3e 100644 --- a/libsrc/meshing/python_mesh.cpp +++ b/libsrc/meshing/python_mesh.cpp @@ -1069,6 +1069,7 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m) })); + m.def("ReadCGNSFile", &ReadCGNSFile, py::arg("filename"), py::arg("base")=1, "Read mesh and solution vectors from CGNS file"); } PYBIND11_MODULE(libmesh, m) { diff --git a/ng/menustat.tcl b/ng/menustat.tcl index 6f870a81..329d59bd 100644 --- a/ng/menustat.tcl +++ b/ng/menustat.tcl @@ -233,6 +233,7 @@ loadmeshinifile; {"TET format" {.tet} } {"STL format" {.stl .stlb} } {"Pro/ENGINEER neutral format" {.fnf} } + {"CFD General Notation System" {.cgns} } } set file [tk_getOpenFile -filetypes $types ] if {$file != ""} { diff --git a/ng/onetcl.cpp b/ng/onetcl.cpp index a0a31da4..bb98f97f 100644 --- a/ng/onetcl.cpp +++ b/ng/onetcl.cpp @@ -868,6 +868,7 @@ DLL_HEADER const char * ngscript[] = {"" ,"{\"TET format\" {.tet} }\n" ,"{\"STL format\" {.stl .stlb} }\n" ,"{\"Pro/ENGINEER neutral format\" {.fnf} }\n" +,"{\"CFD General Notation System\" {.cgns} }\n" ,"}\n" ,"set file [tk_getOpenFile -filetypes $types ]\n" ,"if {$file != \"\"} {\n" diff --git a/tests/build_debug.sh b/tests/build_debug.sh index fe650b8e..349722d8 100755 --- a/tests/build_debug.sh +++ b/tests/build_debug.sh @@ -1,6 +1,12 @@ cd mkdir -p build/netgen cd build/netgen -cmake ../../src/netgen -DUSE_CCACHE=ON -DBUILD_TYPE=DEBUG -DENABLE_UNIT_TESTS=ON -DUSE_OCC=ON +cmake \ + -DUSE_CCACHE=ON \ + -DBUILD_TYPE=DEBUG \ + -DENABLE_UNIT_TESTS=ON \ + -DUSE_OCC=ON \ + -DUSE_CGNS=ON \ + ../../src/netgen make -j12 make install diff --git a/tests/dockerfile b/tests/dockerfile index 3415481f..e14f64ff 100644 --- a/tests/dockerfile +++ b/tests/dockerfile @@ -1,5 +1,5 @@ FROM ubuntu:19.10 ENV DEBIAN_FRONTEND=noninteractive MAINTAINER Matthias Hochsteger -RUN apt-get update && apt-get -y install python3 libpython3-dev libxmu-dev tk-dev tcl-dev cmake git g++ libglu1-mesa-dev ccache python3-pytest python3-numpy python3-tk clang-tidy python3-distutils clang libocct-data-exchange-dev +RUN apt-get update && apt-get -y install python3 libpython3-dev libxmu-dev tk-dev tcl-dev cmake git g++ libglu1-mesa-dev ccache python3-pytest python3-numpy python3-tk clang-tidy python3-distutils clang libocct-data-exchange-dev libcgns-dev ADD . /root/src/netgen From 603141cf1a5cfe045b69d7d455b6c94b49c5c81f Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Wed, 11 Mar 2020 14:53:08 +0000 Subject: [PATCH 011/384] Fix CGNS support on Windows --- .gitlab-ci.yml | 1 + CMakeLists.txt | 2 +- cmake/NetgenConfig.cmake.in | 1 + cmake/SuperBuild.cmake | 5 +++++ cmake/external_projects/cgns.cmake | 15 +++++++++++++++ libsrc/interface/rw_cgns.cpp | 10 +++++----- nglib/CMakeLists.txt | 2 +- 7 files changed, 29 insertions(+), 7 deletions(-) create mode 100644 cmake/external_projects/cgns.cmake diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 8083995f..dc4d724e 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -55,6 +55,7 @@ build_win: cmake %SRC_DIR% -G Ninja -DCMAKE_INSTALL_PREFIX=%INSTALL_DIR% + -DUSE_CGNS=ON -DUSE_OCC=ON -DOCC_LIBRARY=C:/install_opencascade_7.4.0_static/win64/vc14/lib/TKernel.lib -DOCC_INCLUDE_DIR=C:/install_opencascade_7.4.0_static/inc diff --git a/CMakeLists.txt b/CMakeLists.txt index 8f11ccca..14cc43e8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -391,7 +391,7 @@ endif(ENABLE_CPP_CORE_GUIDELINES_CHECK) add_library(netgen_cgns INTERFACE) if(USE_CGNS) - find_library( CGNS_LIBRARY cgns ) + find_library( CGNS_LIBRARY NAMES cgns cgnsdll ) find_path( CGNS_INCLUDE_DIR cgnslib.h ) target_compile_definitions(netgen_cgns INTERFACE NG_CGNS) target_include_directories(netgen_cgns INTERFACE ${CGNS_INCLUDE_DIR}) diff --git a/cmake/NetgenConfig.cmake.in b/cmake/NetgenConfig.cmake.in index e8262666..70206689 100644 --- a/cmake/NetgenConfig.cmake.in +++ b/cmake/NetgenConfig.cmake.in @@ -51,6 +51,7 @@ set(NETGEN_USE_MPI @USE_MPI@) set(NETGEN_USE_OCC @USE_OCC@) set(NETGEN_USE_JPEG @USE_JPEG@) set(NETGEN_USE_MPEG @USE_MPEG@) +set(NETGEN_USE_CGNS @USE_CGNS@) set(NETGEN_INTEL_MIC @INTEL_MIC@) set(NETGEN_INSTALL_PROFILES @INSTALL_PROFILES@) set(NETGEN_USE_CCACHE @USE_CCACHE@) diff --git a/cmake/SuperBuild.cmake b/cmake/SuperBuild.cmake index 83dfe269..36232df2 100644 --- a/cmake/SuperBuild.cmake +++ b/cmake/SuperBuild.cmake @@ -20,6 +20,7 @@ if(WIN32) set (OCC_DOWNLOAD_URL_WIN "${DEPS_DOWNLOAD_URL}/occ_win64.zip" CACHE STRING INTERNAL) set (TCLTK_DOWNLOAD_URL_WIN "${DEPS_DOWNLOAD_URL}/tcltk_win64.zip" CACHE STRING INTERNAL) set (ZLIB_DOWNLOAD_URL_WIN "${DEPS_DOWNLOAD_URL}/zlib_win64.zip" CACHE STRING INTERNAL) + set (CGNS_DOWNLOAD_URL_WIN "${DEPS_DOWNLOAD_URL}/cgns_win64.zip" CACHE STRING INTERNAL) endif(WIN32) if(UNIX) @@ -86,6 +87,10 @@ if(USE_GUI) include(cmake/external_projects/tcltk.cmake) endif(USE_GUI) +if(USE_CGNS) + include(cmake/external_projects/cgns.cmake) +endif(USE_CGNS) + ####################################################################### if(USE_MPI) if(UNIX) diff --git a/cmake/external_projects/cgns.cmake b/cmake/external_projects/cgns.cmake new file mode 100644 index 00000000..fa5fce72 --- /dev/null +++ b/cmake/external_projects/cgns.cmake @@ -0,0 +1,15 @@ +if(WIN32) + + ExternalProject_Add(project_win_cgns + URL ${CGNS_DOWNLOAD_URL_WIN} + UPDATE_COMMAND "" # Disable update + BUILD_IN_SOURCE 1 + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND ${CMAKE_COMMAND} -E copy_directory . ${CMAKE_INSTALL_PREFIX} + LOG_DOWNLOAD 1 + ) + + list(APPEND NETGEN_DEPENDENCIES project_win_cgns) +endif(WIN32) + diff --git a/libsrc/interface/rw_cgns.cpp b/libsrc/interface/rw_cgns.cpp index 7de2aefb..2936f3e8 100644 --- a/libsrc/interface/rw_cgns.cpp +++ b/libsrc/interface/rw_cgns.cpp @@ -30,7 +30,7 @@ namespace netgen::cg case PENTA_15: return 3; default: - throw Exception("Read CGNS: unknown element type " + string(ElementTypeName[type])); + throw Exception("Read CGNS: unknown element type " + string(cg_ElementTypeName(type))); } } @@ -68,7 +68,7 @@ namespace netgen::cg map = map_quad8; break; default: - throw Exception("Read CGNS: unknown element type " + string(ElementTypeName[type])); + throw Exception("Read CGNS: unknown element type " + string(cg_ElementTypeName(type))); } int np; @@ -106,7 +106,7 @@ namespace netgen::cg case HEXA_20: case PENTA_15: default: - throw Exception("Read CGNS: unknown element type " + string(ElementTypeName[type])); + throw Exception("Read CGNS: unknown element type " + string(cg_ElementTypeName(type))); } Element el(np); @@ -130,7 +130,7 @@ namespace netgen::cg case EdgeCenter: return 1; default: - throw Exception("Read CGNS: unknown grid location " + string(GridLocationName[location])); + throw Exception("Read CGNS: unknown grid location " + string(cg_GridLocationName(location))); } } @@ -222,7 +222,7 @@ namespace netgen::cg case KFaceCenter: case EdgeCenter: default: - throw Exception("Read CGNS: unknown grid location " + string(GridLocationName[sol.location])); + throw Exception("Read CGNS: unknown grid location " + string(cg_GridLocationName(sol.location))); } } diff --git a/nglib/CMakeLists.txt b/nglib/CMakeLists.txt index 8fa7444b..a7765e59 100644 --- a/nglib/CMakeLists.txt +++ b/nglib/CMakeLists.txt @@ -31,7 +31,7 @@ endif(NOT WIN32) # target_link_libraries(nglib PRIVATE gen la gprim PUBLIC ngcore) target_link_libraries(nglib PUBLIC ngcore) -target_link_libraries( nglib PRIVATE ${OCC_LIBRARIES} ${MPI_CXX_LIBRARIES} ${OPENGL_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ${X11_Xmu_LIB} ${JPEG_LIBRARIES} ${MKL_LIBRARIES} ${ZLIB_LIBRARIES} ${OCC_LIBRARIES} ) +target_link_libraries( nglib PRIVATE ${OCC_LIBRARIES} ${MPI_CXX_LIBRARIES} ${OPENGL_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ${X11_Xmu_LIB} ${JPEG_LIBRARIES} ${MKL_LIBRARIES} ${ZLIB_LIBRARIES} ${OCC_LIBRARIES} netgen_cgns ) if(USE_OCC AND NOT WIN32) target_link_libraries(nglib PUBLIC occ) From 2615b0911ed4554af0d3436e7ab442fd9bcc6796 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Wed, 11 Mar 2020 16:35:48 +0100 Subject: [PATCH 012/384] Fix CGNS code for version < 3.4 Install libhdf5 on ubuntu test (cgns depends on it) --- CMakeLists.txt | 4 ++++ libsrc/interface/rw_cgns.cpp | 4 ++++ tests/dockerfile | 2 +- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 14cc43e8..3f26e0dd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -396,6 +396,10 @@ if(USE_CGNS) target_compile_definitions(netgen_cgns INTERFACE NG_CGNS) target_include_directories(netgen_cgns INTERFACE ${CGNS_INCLUDE_DIR}) target_link_libraries(netgen_cgns INTERFACE ${CGNS_LIBRARY}) + if(NOT WIN32) # hdf5 is statically linked into cgns in Windows binaries + find_library(HDF5_LIBRARY NAMES hdf5 hdf5_serial) + target_link_libraries(netgen_cgns INTERFACE ${HDF5_LIBRARY}) + endif(NOT WIN32) endif(USE_CGNS) add_subdirectory(libsrc) diff --git a/libsrc/interface/rw_cgns.cpp b/libsrc/interface/rw_cgns.cpp index 2936f3e8..2e45daa4 100644 --- a/libsrc/interface/rw_cgns.cpp +++ b/libsrc/interface/rw_cgns.cpp @@ -291,7 +291,11 @@ namespace netgen::cg cg_ElementDataSize(fn, base, zone, section, &nv); Array vertices(nv); +#if CGNS_VERSION < 3400 + cg_elements_read(fn, base, zone, section, &vertices[0], nullptr); +#else cg_poly_elements_read(fn, base, zone, section, &vertices[0], nullptr, nullptr); +#endif size_t vi = 0; while(vi -RUN apt-get update && apt-get -y install python3 libpython3-dev libxmu-dev tk-dev tcl-dev cmake git g++ libglu1-mesa-dev ccache python3-pytest python3-numpy python3-tk clang-tidy python3-distutils clang libocct-data-exchange-dev libcgns-dev +RUN apt-get update && apt-get -y install python3 libpython3-dev libxmu-dev tk-dev tcl-dev cmake git g++ libglu1-mesa-dev ccache python3-pytest python3-numpy python3-tk clang-tidy python3-distutils clang libocct-data-exchange-dev libcgns-dev libhdf5-dev ADD . /root/src/netgen From 48e4865fee72166e1effbbf8daa24a82270dcea3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20Sch=C3=B6berl?= Date: Wed, 11 Mar 2020 21:33:53 +0100 Subject: [PATCH 013/384] copy BitArray --- libsrc/core/python_ngcore_export.cpp | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/libsrc/core/python_ngcore_export.cpp b/libsrc/core/python_ngcore_export.cpp index d6cc9d6e..953dea59 100644 --- a/libsrc/core/python_ngcore_export.cpp +++ b/libsrc/core/python_ngcore_export.cpp @@ -69,6 +69,29 @@ PYBIND11_MODULE(pyngcore, m) // NOLINT } }, py::arg("inds"), py::arg("value"), "Clear/Set bit at given positions") + .def("__setitem__", [] (BitArray & self, py::slice inds, BitArray & ba) + { + size_t start, step, stop, n; + if (!inds.compute(self.Size(), &start, &stop, &step, &n)) + throw py::error_already_set(); + + if (start == 0 && n == self.Size() && step == 1) + { + self = ba; + } + else + { + for (size_t i = 0; i < n; i++, start += step) + { + bool b = ba.Test(i); + if (b) + self.SetBit(start); + else + self.Clear(start); + } + } + }, py::arg("inds"), py::arg("ba"), "copy BitArray") + .def("__setitem__", [](BitArray & self, IntRange range, bool b) { if (b) From 8fd08ef4ac41edca59ca03ba39924ad5e4f4dbb6 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Wed, 11 Mar 2020 21:30:43 +0100 Subject: [PATCH 014/384] Download prebuilt CGNS library on MacOS --- .gitlab-ci.yml | 1 + CMakeLists.txt | 4 ++-- cmake/SuperBuild.cmake | 13 ++++++------- cmake/external_projects/cgns.cmake | 15 +++++++++++++++ 4 files changed, 24 insertions(+), 9 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index dc4d724e..c50d4eb0 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -243,6 +243,7 @@ build_mac: -DENABLE_UNIT_TESTS=ON -DCMAKE_OSX_DEPLOYMENT_TARGET=10.12 -DCMAKE_OSX_SYSROOT=/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk + -DUSE_CGNS=ON -DUSE_OCC=ON -DOCC_LIBRARY=/usr/local/opt/opencascade-7.4.0/lib/libTKernel.a -DOCC_INCLUDE_DIR=/usr/local/opt/opencascade-7.4.0/include/opencascade diff --git a/CMakeLists.txt b/CMakeLists.txt index 3f26e0dd..fa5450aa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -396,10 +396,10 @@ if(USE_CGNS) target_compile_definitions(netgen_cgns INTERFACE NG_CGNS) target_include_directories(netgen_cgns INTERFACE ${CGNS_INCLUDE_DIR}) target_link_libraries(netgen_cgns INTERFACE ${CGNS_LIBRARY}) - if(NOT WIN32) # hdf5 is statically linked into cgns in Windows binaries + if(NOT WIN32 AND NOT APPLE) # hdf5 is statically linked into cgns in Windows amd MacOS binaries find_library(HDF5_LIBRARY NAMES hdf5 hdf5_serial) target_link_libraries(netgen_cgns INTERFACE ${HDF5_LIBRARY}) - endif(NOT WIN32) + endif(NOT WIN32 AND NOT APPLE) endif(USE_CGNS) add_subdirectory(libsrc) diff --git a/cmake/SuperBuild.cmake b/cmake/SuperBuild.cmake index 36232df2..e28c034b 100644 --- a/cmake/SuperBuild.cmake +++ b/cmake/SuperBuild.cmake @@ -15,13 +15,12 @@ macro(set_vars VAR_OUT) endforeach() endmacro() ####################################################################### -if(WIN32) - set (DEPS_DOWNLOAD_URL "https://github.com/NGSolve/ngsolve_dependencies/releases/download/v1.0.0" CACHE STRING INTERNAL) - set (OCC_DOWNLOAD_URL_WIN "${DEPS_DOWNLOAD_URL}/occ_win64.zip" CACHE STRING INTERNAL) - set (TCLTK_DOWNLOAD_URL_WIN "${DEPS_DOWNLOAD_URL}/tcltk_win64.zip" CACHE STRING INTERNAL) - set (ZLIB_DOWNLOAD_URL_WIN "${DEPS_DOWNLOAD_URL}/zlib_win64.zip" CACHE STRING INTERNAL) - set (CGNS_DOWNLOAD_URL_WIN "${DEPS_DOWNLOAD_URL}/cgns_win64.zip" CACHE STRING INTERNAL) -endif(WIN32) +set (DEPS_DOWNLOAD_URL "https://github.com/NGSolve/ngsolve_dependencies/releases/download/v1.0.0" CACHE STRING INTERNAL) +set (OCC_DOWNLOAD_URL_WIN "${DEPS_DOWNLOAD_URL}/occ_win64.zip" CACHE STRING INTERNAL) +set (TCLTK_DOWNLOAD_URL_WIN "${DEPS_DOWNLOAD_URL}/tcltk_win64.zip" CACHE STRING INTERNAL) +set (ZLIB_DOWNLOAD_URL_WIN "${DEPS_DOWNLOAD_URL}/zlib_win64.zip" CACHE STRING INTERNAL) +set (CGNS_DOWNLOAD_URL_WIN "${DEPS_DOWNLOAD_URL}/cgns_win64.zip" CACHE STRING INTERNAL) +set (CGNS_DOWNLOAD_URL_MAC "${DEPS_DOWNLOAD_URL}/cgns_mac.zip" CACHE STRING INTERNAL) if(UNIX) message("Checking for write permissions in install directory...") diff --git a/cmake/external_projects/cgns.cmake b/cmake/external_projects/cgns.cmake index fa5fce72..f7e74987 100644 --- a/cmake/external_projects/cgns.cmake +++ b/cmake/external_projects/cgns.cmake @@ -13,3 +13,18 @@ if(WIN32) list(APPEND NETGEN_DEPENDENCIES project_win_cgns) endif(WIN32) +if(APPLE) + ExternalProject_Add(project_mac_cgns + URL ${CGNS_DOWNLOAD_URL_MAC} + UPDATE_COMMAND "" # Disable update + BUILD_IN_SOURCE 1 + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND ${CMAKE_COMMAND} -E copy_directory . ${CMAKE_INSTALL_PREFIX} + LOG_DOWNLOAD 1 + ) + + list(APPEND NETGEN_DEPENDENCIES project_mac_cgns) + list(APPEND NETGEN_CMAKE_ARGS "-DCGNS_INCLUDE_DIR=${CMAKE_INSTALL_PREFIX}/Contents/Resources/include") + list(APPEND NETGEN_CMAKE_ARGS "-DCGNS_LIBRARY=${CMAKE_INSTALL_PREFIX}/Contents/MacOS/libcgns.dylib") +endif(APPLE) From 89cb1e07ff2bc8a148fd56939df102983ddf0c63 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Thu, 12 Mar 2020 18:42:58 +0100 Subject: [PATCH 015/384] CGNS reader: Fix boundary/material names for MIXED elements --- libsrc/interface/rw_cgns.cpp | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/libsrc/interface/rw_cgns.cpp b/libsrc/interface/rw_cgns.cpp index 2e45daa4..eb206ee8 100644 --- a/libsrc/interface/rw_cgns.cpp +++ b/libsrc/interface/rw_cgns.cpp @@ -281,11 +281,8 @@ namespace netgen::cg if(type==MIXED) { - bc++; - material++; - mesh.AddFaceDescriptor(FaceDescriptor(bc, 1, 0, 1)); - mesh.SetBCName(bc-1, ngname); - mesh.SetMaterial(material, ngname); + bool have_2d_elements = false; + bool have_3d_elements = false; cgsize_t nv; cg_ElementDataSize(fn, base, zone, section, &nv); @@ -312,6 +309,13 @@ namespace netgen::cg if(dim==2) { + if(!have_2d_elements) + { + bc++; + have_2d_elements = true; + mesh.AddFaceDescriptor(FaceDescriptor(bc, 1, 0, 1)); + mesh.SetBCName(bc-1, ngname); + } auto el = ReadCGNSElement2D(type, vertices.Range(vi, vertices.Size()), first_vertex); el.SetIndex(bc); mesh.AddSurfaceElement(el); @@ -320,6 +324,13 @@ namespace netgen::cg if(dim==3) { + if(!have_3d_elements) + { + material++; + have_3d_elements = true; + mesh.SetMaterial(material, ngname); + } + auto el = ReadCGNSElement3D(type, vertices.Range(vi, vertices.Size()), first_vertex); el.SetIndex(material); mesh.AddVolumeElement(el); From b8d313f056459e3a0ee4c0c498f50b10b63339e3 Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Sun, 15 Mar 2020 18:02:50 +0100 Subject: [PATCH 016/384] identify periodic boundaries --- libsrc/meshing/meshclass.cpp | 42 ++++++++++++++++++++++++++++++++++ libsrc/meshing/meshclass.hpp | 4 ++++ libsrc/meshing/python_mesh.cpp | 1 + 3 files changed, 47 insertions(+) diff --git a/libsrc/meshing/meshclass.cpp b/libsrc/meshing/meshclass.cpp index 8c340041..5c774dfa 100644 --- a/libsrc/meshing/meshclass.cpp +++ b/libsrc/meshing/meshclass.cpp @@ -1,5 +1,6 @@ #include #include +#include #include "meshing.hpp" #ifdef NG_PYTHON @@ -6112,7 +6113,48 @@ namespace netgen // } // #endif + int Mesh::IdentifyPeriodicBoundaries(const string &s1, + const string &s2, + const Transformation<3> &mapping) + { + auto nr = ident->GetMaxNr() + 1; + double lami[4]; + GetElementOfPoint({0,0,0}, lami, true); + set identified_points; + Point3d pmin, pmax; + GetBox(pmin, pmax); + auto eps = 1e-10 * (pmax-pmin).Length(); + for(const auto& se : surfelements) + { + if(GetBCName(se.index-1) != s1) + continue; + for(const auto& pi : se.PNums()) + { + // cout << "pi = " << pi << endl; + if(identified_points.find(pi) != identified_points.end()) + continue; + auto pt = (*this)[pi]; + auto mapped_pt = mapping(pt); + auto other_nr = GetElementOfPoint(mapped_pt, lami); + int index = -1; + auto other_el = VolumeElement(other_nr); + for(auto i : Range(4)) + if((mapped_pt - (*this)[other_el.PNums()[i]]).Length() < eps) + { + index = i; + break; + } + if(index == -1) + throw Exception("Did not find mapped point, are you sure your mesh is periodic?"); + auto other_pi = other_el.PNums()[index]; + identified_points.insert(pi); + ident->Add(pi, other_pi, nr); + // cout << "other pi = " << other_pi << endl; + } + } + return nr; + } void Mesh :: InitPointCurve(double red, double green, double blue) const { diff --git a/libsrc/meshing/meshclass.hpp b/libsrc/meshing/meshclass.hpp index e455f02e..f312a5da 100644 --- a/libsrc/meshing/meshclass.hpp +++ b/libsrc/meshing/meshclass.hpp @@ -710,6 +710,10 @@ namespace netgen FaceDescriptor & GetFaceDescriptor (int i) { return facedecoding.Elem(i); } + int IdentifyPeriodicBoundaries(const string& s1, + const string& s2, + const Transformation<3>& mapping); + // #ifdef NONE // /* // Identify points pi1 and pi2, due to diff --git a/libsrc/meshing/python_mesh.cpp b/libsrc/meshing/python_mesh.cpp index 23cb5d3e..b0ac0c36 100644 --- a/libsrc/meshing/python_mesh.cpp +++ b/libsrc/meshing/python_mesh.cpp @@ -855,6 +855,7 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m) py::arg("pid2"), py::arg("identnr"), py::arg("type")) + .def("IdentifyPeriodicBoundaries", &Mesh::IdentifyPeriodicBoundaries) .def ("CalcLocalH", &Mesh::CalcLocalH) .def ("SetMaxHDomain", [] (Mesh& self, py::list maxhlist) { From ff60ca3f554cd22e85e274ddf02def6c8249f751 Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Tue, 17 Mar 2020 15:32:42 +0100 Subject: [PATCH 017/384] fix identify periodic --- libsrc/meshing/meshclass.cpp | 8 +++----- libsrc/meshing/python_mesh.cpp | 4 ++++ 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/libsrc/meshing/meshclass.cpp b/libsrc/meshing/meshclass.cpp index 5c774dfa..5441b732 100644 --- a/libsrc/meshing/meshclass.cpp +++ b/libsrc/meshing/meshclass.cpp @@ -6118,12 +6118,12 @@ namespace netgen const Transformation<3> &mapping) { auto nr = ident->GetMaxNr() + 1; + ident->SetType(nr, Identifications::PERIODIC); double lami[4]; - GetElementOfPoint({0,0,0}, lami, true); set identified_points; Point3d pmin, pmax; GetBox(pmin, pmax); - auto eps = 1e-10 * (pmax-pmin).Length(); + auto eps = 1e-8 * (pmax-pmin).Length(); for(const auto& se : surfelements) { if(GetBCName(se.index-1) != s1) @@ -6131,12 +6131,11 @@ namespace netgen for(const auto& pi : se.PNums()) { - // cout << "pi = " << pi << endl; if(identified_points.find(pi) != identified_points.end()) continue; auto pt = (*this)[pi]; auto mapped_pt = mapping(pt); - auto other_nr = GetElementOfPoint(mapped_pt, lami); + auto other_nr = GetElementOfPoint(mapped_pt, lami, true); int index = -1; auto other_el = VolumeElement(other_nr); for(auto i : Range(4)) @@ -6150,7 +6149,6 @@ namespace netgen auto other_pi = other_el.PNums()[index]; identified_points.insert(pi); ident->Add(pi, other_pi, nr); - // cout << "other pi = " << other_pi << endl; } } return nr; diff --git a/libsrc/meshing/python_mesh.cpp b/libsrc/meshing/python_mesh.cpp index b0ac0c36..e5a8c5cc 100644 --- a/libsrc/meshing/python_mesh.cpp +++ b/libsrc/meshing/python_mesh.cpp @@ -856,6 +856,10 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m) py::arg("identnr"), py::arg("type")) .def("IdentifyPeriodicBoundaries", &Mesh::IdentifyPeriodicBoundaries) + .def("GetNrIdentifications", [](Mesh& self) + { + return self.GetIdentifications().GetMaxNr(); + }) .def ("CalcLocalH", &Mesh::CalcLocalH) .def ("SetMaxHDomain", [] (Mesh& self, py::list maxhlist) { From bff0e6757653dee5561a29dae0a8a8458beec579 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Tue, 17 Mar 2020 17:05:38 +0100 Subject: [PATCH 018/384] CGNS reader: identify equal points in different zones --- libsrc/interface/rw_cgns.cpp | 101 ++++++++++++++++++++++++++--------- 1 file changed, 75 insertions(+), 26 deletions(-) diff --git a/libsrc/interface/rw_cgns.cpp b/libsrc/interface/rw_cgns.cpp index eb206ee8..dfa24b08 100644 --- a/libsrc/interface/rw_cgns.cpp +++ b/libsrc/interface/rw_cgns.cpp @@ -8,6 +8,8 @@ namespace netgen::cg { + typedef ngcore::ClosedHashTable, size_t> PointTable; + int getDim(ElementType_t type) { switch(type) @@ -34,18 +36,18 @@ namespace netgen::cg } } - Segment ReadCGNSElement1D( ElementType_t type, FlatArray verts, int vert_offset=0 ) + Segment ReadCGNSElement1D( ElementType_t type, FlatArray verts ) { int np; cg_npe(type, &np); Segment s; for (auto i : Range(np)) - s[i] = vert_offset+verts[i]; + s[i] = verts[i]; return s; } - Element2d ReadCGNSElement2D( ElementType_t type, FlatArray verts, int vert_offset=0 ) + Element2d ReadCGNSElement2D( ElementType_t type, FlatArray verts ) { static constexpr int map_tri3[] = {0,2,1}; static constexpr int map_tri6[] = {0,2,1,3,5,4}; // untested @@ -76,11 +78,11 @@ namespace netgen::cg Element2d el(np); for (auto i : Range(np)) - el[i] = vert_offset+verts[map[i]]; + el[i] = verts[map[i]]; return el; } - Element ReadCGNSElement3D( ElementType_t type, FlatArray verts, int vert_offset=0 ) + Element ReadCGNSElement3D( ElementType_t type, FlatArray verts ) { static constexpr int map_tet4[] = {0,2,1,3}; static constexpr int map_prism6[] = {0,2,1,3,5,4}; @@ -111,7 +113,7 @@ namespace netgen::cg Element el(np); for (auto i : Range(np)) - el[i] = vert_offset+verts[map[i]]; + el[i] = verts[map[i]]; return el; } @@ -174,7 +176,7 @@ namespace netgen::cg { ZoneType_t zone_type; int fn, base, zone; - int nv, ne, first_vertex, first_mat, first_bc; + int nv, ne, first_mat, first_bc; Array materials; Array boundaries; string name; @@ -238,23 +240,38 @@ namespace netgen::cg } } - void ReadMesh( Mesh & mesh ) + void ReadMesh( Mesh & mesh, PointTable & point_table ) { static Timer tall("CGNS::ReadMesh-Zone"); RegionTimer rtall(tall); static Timer tsection("CGNS::ReadMesh-Section"); - first_vertex = mesh.GetNP(); first_mat = mesh.GetRegionNamesCD(0).Size(); first_bc = mesh.GetRegionNamesCD(1).Size(); ne = 0; - Array x(nv), y(nv), z(nv); + Array x(nv), y(nv), z(nv); cgsize_t imin=1; - cg_coord_read(fn,base,zone, "CoordinateX", RealSingle, &imin, &nv, &x[0]); - cg_coord_read(fn,base,zone, "CoordinateY", RealSingle, &imin, &nv, &y[0]); - cg_coord_read(fn,base,zone, "CoordinateZ", RealSingle, &imin, &nv, &z[0]); + cg_coord_read(fn,base,zone, "CoordinateX", RealDouble, &imin, &nv, &x[0]); + cg_coord_read(fn,base,zone, "CoordinateY", RealDouble, &imin, &nv, &y[0]); + cg_coord_read(fn,base,zone, "CoordinateZ", RealDouble, &imin, &nv, &z[0]); + + Array point_map(nv); for(auto i : Range(nv)) - mesh.AddPoint( {x[i], y[i], z[i]} ); + { + ngcore::INT<3,size_t> hash = {*reinterpret_cast(&x[i]), *reinterpret_cast(&y[i]), *reinterpret_cast(&z[i])}; + size_t pi_ng; + size_t pos; + // check if this point is new + if( point_table.PositionCreate (hash, pos) ) + { + pi_ng = mesh.AddPoint( {x[i], y[i], z[i]} ); + point_table.SetData(pos, pi_ng); + } + else + point_table.GetData(pos, pi_ng); + + point_map[i] = pi_ng; + } int nsections; cg_nsections(fn, base, zone, &nsections); @@ -264,15 +281,17 @@ namespace netgen::cg for (auto section : Range(1,nsections+1)) { RegionTimer rtsection(tsection); - char name[100]; + char sec_name[100]; ElementType_t type; cgsize_t start, end; int nbndry, parent_flag; - cg_section_read(fn, base, zone, section, name, &type, &start, &end, &nbndry, &parent_flag); - PrintMessage(4, "Read section ", section, " with name ", name, " and element type ", cg_ElementTypeName(type)); + cg_section_read(fn, base, zone, section, sec_name, &type, &start, &end, &nbndry, &parent_flag); + PrintMessage(4, "Read section ", section, " with name ", sec_name, " and element type ", cg_ElementTypeName(type)); + if(name == "Coil" && string(sec_name) == "Top") + continue; - string ngname{name}; + string ngname{sec_name}; for (char & c : ngname) if(c==' ') @@ -300,9 +319,15 @@ namespace netgen::cg auto type = static_cast(vertices[vi++]); int dim = getDim(type); + int np; + cg_npe(type, &np); + + for (auto & v : vertices.Range(vi, vi+np)) + v = point_map[v-1]; + if(dim==1) { - auto el = ReadCGNSElement1D(type, vertices.Range(vi, vertices.Size()), first_vertex); + auto el = ReadCGNSElement1D(type, vertices.Range(vi, vertices.Size())); mesh.AddSegment(el); vi += el.GetNP(); } @@ -316,7 +341,7 @@ namespace netgen::cg mesh.AddFaceDescriptor(FaceDescriptor(bc, 1, 0, 1)); mesh.SetBCName(bc-1, ngname); } - auto el = ReadCGNSElement2D(type, vertices.Range(vi, vertices.Size()), first_vertex); + auto el = ReadCGNSElement2D(type, vertices.Range(vi, vertices.Size())); el.SetIndex(bc); mesh.AddSurfaceElement(el); vi += el.GetNP(); @@ -331,7 +356,7 @@ namespace netgen::cg mesh.SetMaterial(material, ngname); } - auto el = ReadCGNSElement3D(type, vertices.Range(vi, vertices.Size()), first_vertex); + auto el = ReadCGNSElement3D(type, vertices.Range(vi, vertices.Size())); el.SetIndex(material); mesh.AddVolumeElement(el); vi += el.GetNP(); @@ -350,13 +375,15 @@ namespace netgen::cg Array vertices(nv); cg_elements_read(fn, base, zone, section, &vertices[0], nullptr); + for (auto & v : vertices) + v = point_map[v-1]; int ne_section = nv/np; if(dim==1) { for(auto i : Range(ne_section)) { - auto el = ReadCGNSElement1D(type, vertices.Range(np*i, np*(i+1)), first_vertex); + auto el = ReadCGNSElement1D(type, vertices.Range(np*i, np*(i+1))); mesh.AddSegment(el); } } @@ -367,7 +394,7 @@ namespace netgen::cg mesh.AddFaceDescriptor(FaceDescriptor(bc, 1, 0, 1)); for(auto i : Range(ne_section)) { - auto el = ReadCGNSElement2D(type, vertices.Range(np*i, np*(i+1)), first_vertex); + auto el = ReadCGNSElement2D(type, vertices.Range(np*i, np*(i+1))); el.SetIndex(bc); mesh.AddSurfaceElement(el); } @@ -379,7 +406,7 @@ namespace netgen::cg material++; for(auto i : Range(ne_section)) { - auto el = ReadCGNSElement3D(type, vertices.Range(np*i, np*(i+1)), first_vertex); + auto el = ReadCGNSElement3D(type, vertices.Range(np*i, np*(i+1))); el.SetIndex(material); mesh.AddVolumeElement(el); } @@ -407,6 +434,17 @@ namespace netgen int bc = 0; int material = 0; + int n_vertices = 0; + for (auto zi : Range(1, nzones+1)) + { + int size[3]; + char name[100]; + cg_zone_read(fn,base,zi, name, size); + n_vertices += size[0]; + } + + cg::PointTable points(2*n_vertices); + for (auto zi : Range(1, nzones+1)) { ZoneType_t zone_type; @@ -417,7 +455,7 @@ namespace netgen continue; } cg::Zone zone(fn, base, zi); - zone.ReadMesh( mesh ); + zone.ReadMesh( mesh, points ); } } @@ -444,6 +482,17 @@ namespace netgen std::vector> values; std::vector locations; + int n_vertices = 0; + for (auto zi : Range(1, nzones+1)) + { + int size[3]; + char name[100]; + cg_zone_read(fn,base,zi, name, size); + n_vertices += size[0]; + } + + cg::PointTable points(2*n_vertices); + for (auto zi : Range(1, nzones+1)) { ZoneType_t zone_type; @@ -454,7 +503,7 @@ namespace netgen continue; } cg::Zone zone(fn, base, zi); - zone.ReadMesh( *mesh ); + zone.ReadMesh( *mesh, points ); zone.ReadSolutions( names, values, locations ); } From 1f78f900dd4d6943f455f4d8d8ca333583d604d5 Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Thu, 19 Mar 2020 18:12:55 +0100 Subject: [PATCH 019/384] mesh identify periodic for non tet meshes --- libsrc/meshing/meshclass.cpp | 22 +++++++++++++++------- libsrc/meshing/meshclass.hpp | 3 ++- libsrc/meshing/python_mesh.cpp | 3 ++- 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/libsrc/meshing/meshclass.cpp b/libsrc/meshing/meshclass.cpp index 5441b732..b38aeb88 100644 --- a/libsrc/meshing/meshclass.cpp +++ b/libsrc/meshing/meshclass.cpp @@ -6115,15 +6115,19 @@ namespace netgen int Mesh::IdentifyPeriodicBoundaries(const string &s1, const string &s2, - const Transformation<3> &mapping) + const Transformation<3> &mapping, + double pointTolerance) { auto nr = ident->GetMaxNr() + 1; ident->SetType(nr, Identifications::PERIODIC); double lami[4]; set identified_points; - Point3d pmin, pmax; - GetBox(pmin, pmax); - auto eps = 1e-8 * (pmax-pmin).Length(); + if(pointTolerance < 0.) + { + Point3d pmin, pmax; + GetBox(pmin, pmax); + pointTolerance = 1e-8 * (pmax-pmin).Length(); + } for(const auto& se : surfelements) { if(GetBCName(se.index-1) != s1) @@ -6138,14 +6142,18 @@ namespace netgen auto other_nr = GetElementOfPoint(mapped_pt, lami, true); int index = -1; auto other_el = VolumeElement(other_nr); - for(auto i : Range(4)) - if((mapped_pt - (*this)[other_el.PNums()[i]]).Length() < eps) + for(auto i : Range(other_el.PNums().Size())) + if((mapped_pt - (*this)[other_el.PNums()[i]]).Length() < pointTolerance) { index = i; break; } if(index == -1) - throw Exception("Did not find mapped point, are you sure your mesh is periodic?"); + { + cout << "point coordinates = " << pt << endl; + cout << "mapped coordinates = " << mapped_pt << endl; + throw Exception("Did not find mapped point with nr " + ToString(pi) + ", are you sure your mesh is periodic?"); + } auto other_pi = other_el.PNums()[index]; identified_points.insert(pi); ident->Add(pi, other_pi, nr); diff --git a/libsrc/meshing/meshclass.hpp b/libsrc/meshing/meshclass.hpp index f312a5da..28ad665b 100644 --- a/libsrc/meshing/meshclass.hpp +++ b/libsrc/meshing/meshclass.hpp @@ -712,7 +712,8 @@ namespace netgen int IdentifyPeriodicBoundaries(const string& s1, const string& s2, - const Transformation<3>& mapping); + const Transformation<3>& mapping, + double pointTolerance); // #ifdef NONE // /* diff --git a/libsrc/meshing/python_mesh.cpp b/libsrc/meshing/python_mesh.cpp index e5a8c5cc..542e7088 100644 --- a/libsrc/meshing/python_mesh.cpp +++ b/libsrc/meshing/python_mesh.cpp @@ -855,7 +855,8 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m) py::arg("pid2"), py::arg("identnr"), py::arg("type")) - .def("IdentifyPeriodicBoundaries", &Mesh::IdentifyPeriodicBoundaries) + .def("IdentifyPeriodicBoundaries", &Mesh::IdentifyPeriodicBoundaries, + py::arg("face1"), py::arg("face2"), py::arg("mapping"), py::arg("point_tolerance") = -1.) .def("GetNrIdentifications", [](Mesh& self) { return self.GetIdentifications().GetMaxNr(); From b1d65912ec118ac541a5a459180fe6c5d15c3e63 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Thu, 19 Mar 2020 20:50:27 +0100 Subject: [PATCH 020/384] cgns: flip normals of 2d elements --- libsrc/interface/rw_cgns.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsrc/interface/rw_cgns.cpp b/libsrc/interface/rw_cgns.cpp index dfa24b08..7e55b550 100644 --- a/libsrc/interface/rw_cgns.cpp +++ b/libsrc/interface/rw_cgns.cpp @@ -78,7 +78,7 @@ namespace netgen::cg Element2d el(np); for (auto i : Range(np)) - el[i] = verts[map[i]]; + el[i] = verts[i]; return el; } From a52ccd7ce54ca60de93fb43874e87e5865d81624 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Wed, 25 Mar 2020 10:40:12 +0100 Subject: [PATCH 021/384] Fix build with USE_NUMA=ON --- CMakeLists.txt | 1 + cmake/NetgenConfig.cmake.in | 2 ++ libsrc/core/CMakeLists.txt | 6 ++++++ libsrc/core/taskmanager.hpp | 6 ++++++ 4 files changed, 15 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index fa5450aa..60d82727 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,6 +18,7 @@ option( USE_OCC "(not supported) compile with OpenCascade geometry kernel" O option( USE_JPEG "enable snapshots using library libjpeg" OFF ) option( USE_MPEG "enable video recording with FFmpeg, uses libavcodec" OFF ) option( USE_CGNS "enable CGNS file read/write support" OFF ) +option( USE_NUMA "compile with NUMA-aware code") option( INTEL_MIC "cross compile for intel xeon phi") option( INSTALL_PROFILES "install environment variable settings to /etc/profile.d" OFF ) option( USE_CCACHE "use ccache") diff --git a/cmake/NetgenConfig.cmake.in b/cmake/NetgenConfig.cmake.in index 70206689..54f88ac3 100644 --- a/cmake/NetgenConfig.cmake.in +++ b/cmake/NetgenConfig.cmake.in @@ -27,6 +27,7 @@ set(NETGEN_METIS_LIBRARY "@METIS_LIBRARY@") set(NETGEN_MKL_LIBRARIES "@MKL_LIBRARIES@") set(NETGEN_MPI_CXX_INCLUDE_PATH "@MPI_CXX_INCLUDE_PATH@") set(NETGEN_MPI_CXX_LIBRARIES "@MPI_CXX_LIBRARIES@") +set(NETGEN_NUMA_LIBRARY "@NUMA_LIBRARY@") set(NETGEN_OCC_INCLUDE_DIR "@OCC_INCLUDE_DIR@") set(NETGEN_OCC_LIBRARIES_BIN "@OCC_LIBRARIES_BIN@") set(NETGEN_OCC_LIBRARIES "@OCC_LIBRARIES@") @@ -56,6 +57,7 @@ set(NETGEN_INTEL_MIC @INTEL_MIC@) set(NETGEN_INSTALL_PROFILES @INSTALL_PROFILES@) set(NETGEN_USE_CCACHE @USE_CCACHE@) set(NETGEN_USE_NATIVE_ARCH @USE_NATIVE_ARCH@) +set(NETGEN_USE_NUMA @USE_NUMA@) set(NETGEN_PYTHON_RPATH "@NETGEN_PYTHON_RPATH@") set(NETGEN_RPATH_TOKEN "@NG_RPATH_TOKEN@") diff --git a/libsrc/core/CMakeLists.txt b/libsrc/core/CMakeLists.txt index cb5eb36c..8a36ba13 100644 --- a/libsrc/core/CMakeLists.txt +++ b/libsrc/core/CMakeLists.txt @@ -51,6 +51,12 @@ if(USE_SPDLOG) endif(DEBUG_LOG) endif(USE_SPDLOG) +if(USE_NUMA) + find_library(NUMA_LIBRARY libnuma.so) + target_compile_definitions(ngcore PUBLIC USE_NUMA) + target_link_libraries(ngcore PRIVATE ${NUMA_LIBRARY}) +endif(USE_NUMA) + install(TARGETS ngcore DESTINATION ${NG_INSTALL_DIR} COMPONENT netgen) target_link_libraries(ngcore PUBLIC netgen_mpi PRIVATE netgen_python ${CMAKE_THREAD_LIBS_INIT}) diff --git a/libsrc/core/taskmanager.hpp b/libsrc/core/taskmanager.hpp index 4ba656c3..d9239be9 100644 --- a/libsrc/core/taskmanager.hpp +++ b/libsrc/core/taskmanager.hpp @@ -17,6 +17,12 @@ #include "paje_trace.hpp" #include "profiler.hpp" +#ifdef USE_NUMA +#include +#include +#endif + + namespace ngcore { using std::atomic; From cb015c95d05198d3d7b9571aba58b45539a47503 Mon Sep 17 00:00:00 2001 From: Michael Date: Mon, 30 Mar 2020 20:44:39 +0200 Subject: [PATCH 022/384] export update method for mesh --- libsrc/meshing/python_mesh.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libsrc/meshing/python_mesh.cpp b/libsrc/meshing/python_mesh.cpp index 542e7088..7e1f4821 100644 --- a/libsrc/meshing/python_mesh.cpp +++ b/libsrc/meshing/python_mesh.cpp @@ -1016,6 +1016,10 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m) res["tet"] = py::make_tuple( values[2], values[3] ); return res; }, py::arg("badelement_limit")=175.0) + .def ("Update", [](Mesh & self) + { + self.SetNextTimeStamp(); + }) .def ("CalcTotalBadness", &Mesh::CalcTotalBad) .def ("GetQualityHistogram", &Mesh::GetQualityHistogram) ; From d74061dd2352e07f805a2912a0ee3544aaea494b Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Mon, 6 Apr 2020 12:43:42 +0200 Subject: [PATCH 023/384] python str method for arrays --- libsrc/core/python_ngcore.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libsrc/core/python_ngcore.hpp b/libsrc/core/python_ngcore.hpp index 44bf0362..92cbbe62 100644 --- a/libsrc/core/python_ngcore.hpp +++ b/libsrc/core/python_ngcore.hpp @@ -142,6 +142,10 @@ namespace ngcore return py::make_iterator (self.begin(),self.end()); }, py::keep_alive<0,1>()) // keep array alive while iterator is used + .def("__str__", [](TFlat& self) + { + return ToString(self); + }) ; if constexpr (detail::HasPyFormat::value) From b46ec8dc7b55f7c29414b35e4b45f6c53079b594 Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Sat, 18 Apr 2020 13:40:19 +0200 Subject: [PATCH 024/384] fix printing of 1 based arrays --- libsrc/core/array.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libsrc/core/array.hpp b/libsrc/core/array.hpp index 67b46a72..ccafef6b 100644 --- a/libsrc/core/array.hpp +++ b/libsrc/core/array.hpp @@ -600,8 +600,8 @@ namespace ngcore FlatArray View (FlatArray fa) { return fa; } /// print array - template - inline ostream & operator<< (ostream & s, const FlatArray & a) + template + inline ostream & operator<< (ostream & s, const FlatArray & a) { for (auto i : a.Range()) s << i << ": " << a[i] << "\n"; From 83a48af36adce05d947b79a1726b35e3519f748b Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Sun, 19 Apr 2020 19:26:44 +0200 Subject: [PATCH 025/384] add safety check for FindEdges --- libsrc/csg/edgeflw.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libsrc/csg/edgeflw.cpp b/libsrc/csg/edgeflw.cpp index d89e2fd9..644d2cfa 100644 --- a/libsrc/csg/edgeflw.cpp +++ b/libsrc/csg/edgeflw.cpp @@ -1255,6 +1255,9 @@ namespace netgen *testout << "Refsegments, before delete: " << endl << refedges << endl; *testout << "inv: " << endl << refedgesinv << endl; } + + if(refedges.Size() == 0) + throw Exception("No edges found, something wrong."); NgBitArray todelete(refedges.Size()); todelete.Clear(); From 58e6e5dc182971efba7183cfed5ee49f224c382f Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Sun, 19 Apr 2020 20:00:06 +0200 Subject: [PATCH 026/384] modernize and improve GenerateBoundaryLayer --- libsrc/meshing/boundarylayer.cpp | 819 ++++++++++++----------------- libsrc/meshing/boundarylayer.hpp | 17 +- libsrc/meshing/python_mesh.cpp | 127 +++-- libsrc/meshing/topology.hpp | 2 +- ng/ngpkg.cpp | 17 +- tests/pytest/test_boundarylayer.py | 17 + 6 files changed, 460 insertions(+), 539 deletions(-) create mode 100644 tests/pytest/test_boundarylayer.py diff --git a/libsrc/meshing/boundarylayer.cpp b/libsrc/meshing/boundarylayer.cpp index 4d132615..0d61d4cc 100644 --- a/libsrc/meshing/boundarylayer.cpp +++ b/libsrc/meshing/boundarylayer.cpp @@ -103,24 +103,16 @@ namespace netgen function, in order to calculate the effective direction in which the prismatic layer should grow */ - void GetSurfaceNormal(Mesh & mesh, const Element2d & el, int Vertex, Vec3d & SurfaceNormal) + Vec<3> GetSurfaceNormal(Mesh & mesh, const Element2d & el) { - int Vertex_A; - int Vertex_B; - - Vertex_A = Vertex + 1; - if(Vertex_A > el.GetNP()) Vertex_A = 1; - - Vertex_B = Vertex - 1; - if(Vertex_B <= 0) Vertex_B = el.GetNP(); - - Vec3d Vect_A,Vect_B; - - Vect_A = mesh[el.PNum(Vertex_A)] - mesh[el.PNum(Vertex)]; - Vect_B = mesh[el.PNum(Vertex_B)] - mesh[el.PNum(Vertex)]; - - SurfaceNormal = Cross(Vect_A,Vect_B); - SurfaceNormal.Normalize(); + auto v0 = mesh[el[0]]; + auto v1 = mesh[el[1]]; + auto v2 = mesh[el[2]]; + Vec<3> vec1 = v1-v0; + Vec<3> vec2 = v2-v0; + Vec<3> normal = Cross(vec1, vec2); + normal.Normalize(); + return normal; } @@ -141,507 +133,390 @@ namespace netgen Currently, the layer height is calculated using: height = h_first_layer * (growth_factor^(num_layers - 1)) */ - void GenerateBoundaryLayer (Mesh & mesh, BoundaryLayerParameters & blp) + void GenerateBoundaryLayer (Mesh & mesh, const BoundaryLayerParameters & blp) { - ofstream dbg("BndLayerDebug.log"); - - // Angle between a surface element and a growth-vector below which + // Angle between a surface element and a growth-vector below which // a prism is project onto that surface as a quad // (in degrees) double angleThreshold = 5.0; - - NgArray surfid (blp.surfid); - int prismlayers = blp.prismlayers; - double hfirst = blp.hfirst; - double growthfactor = blp.growthfactor; - NgArray heights (blp.heights); - - bool grow_edges = false; // grow layer at edges - - - // Monitor and print out the number of prism and quad elements + // Monitor and print out the number of prism and quad elements // added to the mesh int numprisms = 0; int numquads = 0; - - cout << "Old NP: " << mesh.GetNP() << endl; - cout << "Old NSE: " << mesh.GetNSE() << endl; - - for(int layer = prismlayers; layer >= 1; layer--) + PrintMessage(1, "Generating boundary layer..."); + PrintMessage(3, "Old NP: ", mesh.GetNP()); + PrintMessage(3, "Old NSE: ",mesh.GetNSE()); + + for(int layer = blp.heights.Size(); layer >= 1; layer--) { - cout << "Generating layer: " << layer << endl; - - const MeshTopology& meshtopo = mesh.GetTopology(); - const_cast (meshtopo).SetBuildEdges(true); - const_cast (meshtopo).SetBuildFaces(true); - const_cast (meshtopo).Update(); + PrintMessage(3, "Generating layer: ", layer); - double layerht = hfirst; - - if(heights.Size()>0) + mesh.UpdateTopology(); + auto& meshtopo = mesh.GetTopology(); + + auto layerht = blp.heights[layer-1]; + + PrintMessage(5, "Layer Height = ", layerht); + + // Need to store the old number of points and + // surface elements because there are new points and + // surface elements being added during the process + int np = mesh.GetNP(); + int nse = mesh.GetNSE(); + int ne = mesh.GetNE(); + + // Safety measure to ensure no issues with mesh + // consistency + int nseg = mesh.GetNSeg(); + + // Indicate which points need to be remapped + BitArray bndnodes(np+1); // big enough for 1-based array + + // Map of the old points to the new points + Array mapto(np); + + // Growth vectors for the prismatic layer based on + // the effective surface normal at a given point + Array, PointIndex> growthvectors(np); + Array>, PointIndex> all_growthvectors(np); + + // Bit array to identify all the points belonging + // to the surface of interest + bndnodes.Clear(); + + // Run through all the surface elements and mark the points + // belonging to those where a boundary layer has to be created. + // In addition, also calculate the effective surface normal + // vectors at each of those points to determine the mesh motion + // direction + PrintMessage(3, "Marking points for remapping..."); + + for(const auto& sel : mesh.SurfaceElements()) + if (blp.surfid.Contains(sel.GetIndex())) + { + auto normal = GetSurfaceNormal(mesh,sel); + if(!blp.outside) + normal *= -1; + for(int j : Range(sel.PNums())) + { + // Set the bitarray to indicate that the + // point is part of the required set + bndnodes.SetBit(sel[j]); + + // Add the surface normal to the already existent one + // (This gives the effective normal direction at corners + // and curved areas) + all_growthvectors[sel[j]].Append(normal); + } + } + + if (!blp.grow_edges) + for(const auto& sel : mesh.SurfaceElements()) + { + bndnodes.Clear(sel[0]); + bndnodes.Clear(sel[1]); + } + + // Add additional points into the mesh structure in order to + // clone the surface elements. + // Also invert the growth vectors so that they point inwards, + // and normalize them + PrintMessage(3, "Cloning points and calculating growth vectors..."); + + for (PointIndex pi = 1; pi <= np; pi++) { - layerht = heights[layer-1]; - } - else - { - if(growthfactor == 1) + if (bndnodes.Test(pi)) { - layerht = layer * hfirst; + mapto[pi] = mesh.AddPoint(mesh[pi]); + growthvectors[pi] = all_growthvectors[pi][0]; + for(int i = 1; i < all_growthvectors[pi].Size(); i++) + { + auto& veci = all_growthvectors[pi][i]; + for(auto j : Range(i)) + { + auto& vecj = all_growthvectors[pi][j]; + veci -= 1./(vecj.Length()+1e-10) * (veci * vecj) * vecj; + } + growthvectors[pi] += veci; + } + // growthvectors[pi].Normalize(); + // growthvectors[pi] *= -1.0; } else { - layerht = hfirst*(pow(growthfactor,(layer+1)) - 1)/(growthfactor - 1); + mapto[pi].Invalidate(); + growthvectors[pi] = {0,0,0}; } } - - cout << "Layer Height = " << layerht << endl; - - // Need to store the old number of points and - // surface elements because there are new points and - // surface elements being added during the process - int np = mesh.GetNP(); - int nse = mesh.GetNSE(); - int ne = mesh.GetNE(); - - // Safety measure to ensure no issues with mesh - // consistency - int nseg = mesh.GetNSeg(); - - // Indicate which points need to be remapped - NgBitArray bndnodes(np+1); // big enough for 1-based array - - // Map of the old points to the new points - NgArray mapto(np); - - // Growth vectors for the prismatic layer based on - // the effective surface normal at a given point - NgArray growthvectors(np); - - // Bit array to identify all the points belonging - // to the surface of interest - bndnodes.Clear(); - - // Run through all the surface elements and mark the points - // belonging to those where a boundary layer has to be created. - // In addition, also calculate the effective surface normal - // vectors at each of those points to determine the mesh motion - // direction - cout << "Marking points for remapping...." << endl; - - for (SurfaceElementIndex si = 0; si < nse; si++) - if (surfid.Contains(mesh[si].GetIndex())) - { - const Element2d & sel = mesh[si]; - for(int j = 0; j < sel.GetNP(); j++) - { - // Set the bitarray to indicate that the - // point is part of the required set - bndnodes.Set(sel[j]); - Vec3d surfacenormal; - - // Calculate the surface normal at the current point - // with respect to the current surface element - GetSurfaceNormal(mesh,sel,j+1,surfacenormal); - - // Add the surface normal to the already existent one - // (This gives the effective normal direction at corners - // and curved areas) - growthvectors[sel[j]] += surfacenormal; - } - } - - if (!grow_edges) - for (SegmentIndex sei = 0; sei <= nseg; sei++) - { - bndnodes.Clear (mesh[sei][0]); - bndnodes.Clear (mesh[sei][1]); - } - - // Add additional points into the mesh structure in order to - // clone the surface elements. - // Also invert the growth vectors so that they point inwards, - // and normalize them - cout << "Cloning points and calculating growth vectors...." << endl; - - for (PointIndex pi = 1; pi <= np; pi++) - { - if (bndnodes.Test(pi)) - { - mapto[pi] = mesh.AddPoint (mesh[pi]); - - growthvectors[pi].Normalize(); - growthvectors[pi] *= -1.0; - } - else - { - mapto[pi] = 0; - growthvectors[pi] = Vec3d(0,0,0); - } - } - // Add quad surface elements at edges for surfaces which - // don't have boundary layers + // Add quad surface elements at edges for surfaces which + // don't have boundary layers - // Bit array to keep track of segments already processed - NgBitArray segsel(nseg); + // Bit array to keep track of segments already processed + BitArray segsel(nseg); - // Set them all to "1" to initially activate all segments - segsel.Set(); + // Set them all to "1" to initially activate all segments + segsel.Set(); - cout << "Adding 2D Quad elements on required surfaces...." << endl; + PrintMessage(3, "Adding 2D Quad elements on required surfaces..."); - if (grow_edges) - for (SegmentIndex sei = 0; sei <= nseg; sei++) - { - PointIndex seg_p1 = mesh[sei][0]; - PointIndex seg_p2 = mesh[sei][1]; - - // Only go in if the segment is still active, and if both its - // surface index is part of the "hit-list" - if(segsel.Test(sei) && surfid.Contains(mesh[sei].si)) - { - // clear the bit to indicate that this segment has been processed - segsel.Clear(sei); - - // Find matching segment pair on other surface - for (SegmentIndex sej = 0; sej < nseg; sej++) - { - PointIndex segpair_p1 = mesh[sej][1]; - PointIndex segpair_p2 = mesh[sej][0]; - - // Find the segment pair on the neighbouring surface element - // Identified by: seg1[0] = seg_pair[1] and seg1[1] = seg_pair[0] - if(segsel.Test(sej) && ((segpair_p1 == seg_p1) && (segpair_p2 == seg_p2))) - { - // clear bit to indicate that processing of this segment is done - segsel.Clear(sej); - - // Only worry about those surfaces which are not in the - // boundary layer list - if(!surfid.Contains(mesh[sej].si)) - { - SurfaceElementIndex pnt_commelem = 0; - NgArray pnt1_elems; - NgArray pnt2_elems; - - - meshtopo.GetVertexSurfaceElements(segpair_p1,pnt1_elems); - meshtopo.GetVertexSurfaceElements(segpair_p2,pnt2_elems); + if(blp.grow_edges) + for(SegmentIndex sei = 0; sei < nseg; sei++) + { + PointIndex seg_p1 = mesh[sei][0]; + PointIndex seg_p2 = mesh[sei][1]; - for(int k = 0; k < pnt1_elems.Size(); k++) - { - const Element2d & pnt1_sel = mesh.SurfaceElement(pnt1_elems[k]); - for(int l = 0; l < pnt2_elems.Size(); l++) - { - const Element2d & pnt2_sel = mesh.SurfaceElement(pnt2_elems[l]); - if((pnt1_sel.GetIndex() == mesh[sej].si) - && (pnt2_sel.GetIndex() == mesh[sej].si) - && (pnt1_elems[k] == pnt2_elems[l])) - { - pnt_commelem = pnt1_elems[k]; - } - } - } + // Only go in if the segment is still active, and if both its + // surface index is part of the "hit-list" + if(segsel.Test(sei) && blp.surfid.Contains(mesh[sei].si)) + { + // clear the bit to indicate that this segment has been processed + segsel.Clear(sei); - /* - int pnum_commelem = 0; - for(int k = 1; k <= mesh.SurfaceElement(pnt_commelem).GetNP(); k++) - { - if((mesh.SurfaceElement(pnt_commelem).PNum(k) != segpair_p1) - && (mesh.SurfaceElement(pnt_commelem).PNum(k) != segpair_p2)) - { - pnum_commelem = mesh.SurfaceElement(pnt_commelem).PNum(k); - } - } - */ - - Vec3d surfelem_vect, surfelem_vect1; - - const Element2d & commsel = mesh.SurfaceElement(pnt_commelem); - - dbg << "NP= " << commsel.GetNP() << " : "; - - for(int k = 1; k <= commsel.GetNP(); k++) - { - GetSurfaceNormal(mesh,commsel,k,surfelem_vect1); - surfelem_vect += surfelem_vect1; - } - - surfelem_vect.Normalize(); - - double surfangle = Angle(growthvectors.Elem(segpair_p1),surfelem_vect); - - dbg << "V1= " << surfelem_vect1 - << " : V2= " << surfelem_vect1 - << " : V= " << surfelem_vect - << " : GV= " << growthvectors.Elem(segpair_p1) - << " : Angle= " << surfangle * 180 / 3.141592; - - - // remap the segments to the new points - mesh[sei][0] = mapto[seg_p1]; - mesh[sei][1] = mapto[seg_p2]; - mesh[sej][1] = mapto[seg_p1]; - mesh[sej][0] = mapto[seg_p2]; - - if((surfangle < (90 + angleThreshold) * 3.141592 / 180.0) - && (surfangle > (90 - angleThreshold) * 3.141592 / 180.0)) - { - dbg << " : quad\n"; - // Since the surface is lower than the threshold, change the effective - // prism growth vector to match with the surface vector, so that - // the Quad which is created lies on the original surface - //growthvectors.Elem(segpair_p1) = surfelem_vect; - - // Add a quad element to account for the prism volume - // element which is going to be added - Element2d sel(QUAD); - sel.PNum(4) = mapto[seg_p1]; - sel.PNum(3) = mapto[seg_p2]; - sel.PNum(2) = segpair_p2; - sel.PNum(1) = segpair_p1; - sel.SetIndex(mesh[sej].si); - mesh.AddSurfaceElement(sel); - numquads++; - } - else - { - dbg << "\n"; - for (int k = 0; k < pnt1_elems.Size(); k++) - { - Element2d & pnt_sel = mesh.SurfaceElement(pnt1_elems[k]); - if(pnt_sel.GetIndex() == mesh[sej].si) - { - for(int l = 0; l < pnt_sel.GetNP(); l++) - { - if(pnt_sel[l] == segpair_p1) - pnt_sel[l] = mapto[seg_p1]; - else if (pnt_sel[l] == segpair_p2) - pnt_sel[l] = mapto[seg_p2]; - } - } - } - - for (int k = 0; k < pnt2_elems.Size(); k++) - { - Element2d & pnt_sel = mesh.SurfaceElement(pnt2_elems[k]); - if(pnt_sel.GetIndex() == mesh[sej].si) - { - for(int l = 0; l < pnt_sel.GetNP(); l++) - { - if(pnt_sel[l] == segpair_p1) - pnt_sel[l] = mapto.Get(seg_p1); - else if (pnt_sel[l] == segpair_p2) - pnt_sel[l] = mapto.Get(seg_p2); - } - } - } - } - // } - } - else - { - // If the code comes here, it indicates that we are at - // a line segment pair which is at the intersection - // of two surfaces, both of which have to grow boundary - // layers.... here too, remapping the segments to the - // new points is required - mesh[sei][0] = mapto.Get(seg_p1); - mesh[sei][1] = mapto.Get(seg_p2); - mesh[sej][1] = mapto.Get(seg_p1); - mesh[sej][0] = mapto.Get(seg_p2); - } - } - } - } - } - - // Add prismatic cells at the boundaries - cout << "Generating prism boundary layer volume elements...." << endl; + // Find matching segment pair on other surface + for (SegmentIndex sej = 0; sej < nseg; sej++) + { + PointIndex segpair_p1 = mesh[sej][1]; + PointIndex segpair_p2 = mesh[sej][0]; - for (SurfaceElementIndex si = 0; si < nse; si++) - { - Element2d & sel = mesh.SurfaceElement(si); - if(surfid.Contains(sel.GetIndex())) - { - /* - Element el(PRISM); - for (int j = 0; j < sel.GetNP(); j++) - { - // Check (Doublecheck) if the corresponding point has a - // copy available for remapping - if (mapto.Get(sel[j])) - { - // Define the points of the newly added Prism cell - el[j+3] = mapto[sel[j]]; - el[j] = sel[j]; - } - else - { - el[j+3] = sel[j]; - el[j] = sel[j]; - } - } - - el.SetIndex(1); - el.Invert(); - mesh.AddVolumeElement(el); - numprisms++; - */ - // cout << "add element: " << endl; - int classify = 0; - for (int j = 0; j < 3; j++) - if (mapto[sel[j]]) - classify += (1 << j); + // Find the segment pair on the neighbouring surface element + // Identified by: seg1[0] = seg_pair[1] and seg1[1] = seg_pair[0] + if(segsel.Test(sej) && ((segpair_p1 == seg_p1) && (segpair_p2 == seg_p2))) + { + // clear bit to indicate that processing of this segment is done + segsel.Clear(sej); - // cout << "classify = " << classify << endl; + // Only worry about those surfaces which are not in the + // boundary layer list + if(!blp.surfid.Contains(mesh[sej].si)) + { + SurfaceElementIndex pnt_commelem; + SetInvalid(pnt_commelem); - ELEMENT_TYPE types[] = { PRISM, TET, TET, PYRAMID, - TET, PYRAMID, PYRAMID, PRISM }; - int nums[] = { sel[0], sel[1], sel[2], mapto[sel[0]], mapto[sel[1]], mapto[sel[2]] }; - int vertices[][6] = - { + auto pnt1_elems = meshtopo.GetVertexSurfaceElements(segpair_p1); + auto pnt2_elems = meshtopo.GetVertexSurfaceElements(segpair_p2); + + for(auto pnt1_sei : pnt1_elems) + { + const auto& pnt1_sel = mesh[pnt1_sei]; + for(auto pnt2_sei : pnt2_elems) + { + const Element2d & pnt2_sel = mesh.SurfaceElement(pnt2_sei); + if((pnt1_sel.GetIndex() == mesh[sej].si) + && (pnt2_sel.GetIndex() == mesh[sej].si) + && (pnt1_sei == pnt2_sei)) + { + pnt_commelem = pnt1_sei; + } + } + } + + const Element2d & commsel = mesh.SurfaceElement(pnt_commelem); + auto surfelem_vect = GetSurfaceNormal(mesh, commsel); + if(blp.outside) + surfelem_vect *= -1; + + double surfangle = Angle(growthvectors[segpair_p1],surfelem_vect); + // remap the segments to the new points + if(!blp.outside) + { + mesh[sei][0] = mapto[seg_p1]; + mesh[sei][1] = mapto[seg_p2]; + mesh[sej][1] = mapto[seg_p1]; + mesh[sej][0] = mapto[seg_p2]; + } + + if((surfangle < (90 + angleThreshold) * 3.141592 / 180.0) + && (surfangle > (90 - angleThreshold) * 3.141592 / 180.0)) + { + // Since the surface is lower than the threshold, change the effective + // prism growth vector to match with the surface vector, so that + // the Quad which is created lies on the original surface + //growthvectors.Elem(segpair_p1) = surfelem_vect; + + // Add a quad element to account for the prism volume + // element which is going to be added + Element2d sel(QUAD); + if(blp.outside) + Swap(seg_p1, seg_p2); + sel.PNum(4) = mapto[seg_p1]; + sel.PNum(3) = mapto[seg_p2]; + sel.PNum(2) = seg_p2; + sel.PNum(1) = seg_p1; + sel.SetIndex(mesh[sej].si); + mesh.AddSurfaceElement(sel); + numquads++; + } + else + { + for (int k = 0; k < pnt1_elems.Size(); k++) + { + Element2d & pnt_sel = mesh.SurfaceElement(pnt1_elems[k]); + if(pnt_sel.GetIndex() == mesh[sej].si) + { + for(int l = 0; l < pnt_sel.GetNP(); l++) + { + if(pnt_sel[l] == segpair_p1) + pnt_sel[l] = mapto[seg_p1]; + else if (pnt_sel[l] == segpair_p2) + pnt_sel[l] = mapto[seg_p2]; + } + } + } + + for (int k = 0; k < pnt2_elems.Size(); k++) + { + Element2d & pnt_sel = mesh.SurfaceElement(pnt2_elems[k]); + if(pnt_sel.GetIndex() == mesh[sej].si) + { + for(int l = 0; l < pnt_sel.GetNP(); l++) + { + if(pnt_sel[l] == segpair_p1) + pnt_sel[l] = mapto[seg_p1]; + else if (pnt_sel[l] == segpair_p2) + pnt_sel[l] = mapto[seg_p2]; + } + } + } + } + // } + } + else + { + // If the code comes here, it indicates that we are at + // a line segment pair which is at the intersection + // of two surfaces, both of which have to grow boundary + // layers.... here too, remapping the segments to the + // new points is required + mesh[sei][0] = mapto[seg_p1]; + mesh[sei][1] = mapto[seg_p2]; + mesh[sej][1] = mapto[seg_p1]; + mesh[sej][0] = mapto[seg_p2]; + } + } + } + } + } + + // Add prismatic cells at the boundaries + PrintMessage(3, "Generating prism boundary layer volume elements..."); + + for (SurfaceElementIndex si = 0; si < nse; si++) + { + Element2d & sel = mesh.SurfaceElement(si); + if(blp.surfid.Contains(sel.GetIndex())) + { + int classify = 0; + for (int j = 0; j < 3; j++) + if (mapto[sel[j]].IsValid()) + classify += (1 << j); + + // cout << "classify = " << classify << endl; + + ELEMENT_TYPE types[] = { PRISM, TET, TET, PYRAMID, + TET, PYRAMID, PYRAMID, PRISM }; + int nums[] = { sel[0], sel[1], sel[2], mapto[sel[0]], mapto[sel[1]], mapto[sel[2]] }; + int vertices[][6] = + { { 0, 1, 2, 0, 1, 2 }, // should not occur { 0, 2, 1, 3, 0, 0 }, { 0, 2, 1, 4, 0, 0 }, { 0, 1, 4, 3, 2, 0 }, { 0, 2, 1, 5, 0, 0 }, - { 2, 0, 3, 5, 1, 0 }, + { 2, 0, 3, 5, 1, 0 }, { 1, 2, 5, 4, 0, 0 }, { 0, 2, 1, 3, 5, 4 } - }; + }; + if(blp.outside) + { + if(classify != 7) + throw Exception("Outside with non prisms not yet implemented"); + for(auto i : Range(6)) + vertices[7][i] = i; + } - Element el(types[classify]); - for (int i = 0; i < 6; i++) - el[i] = nums[vertices[classify][i]]; - if(blp.new_matnrs.Size() > 0) - el.SetIndex(blp.new_matnrs[layer-1]); - else - el.SetIndex(blp.new_matnr); - // cout << "el = " << el << endl; - if (classify != 0) - mesh.AddVolumeElement(el); - } - } - - // Finally switch the point indices of the surface elements - // to the newly added ones - cout << "Transferring boundary layer surface elements to new vertex references...." << endl; - - for (int i = 1; i <= nse; i++) - { - Element2d & sel = mesh.SurfaceElement(i); - if(surfid.Contains(sel.GetIndex())) - { - for (int j = 1; j <= sel.GetNP(); j++) - { - // Check (Doublecheck) if the corresponding point has a + Element el(types[classify]); + for (int i = 0; i < 6; i++) + el[i] = nums[vertices[classify][i]]; + el.SetIndex(blp.new_matnrs[layer-1]); + if (classify != 0) + mesh.AddVolumeElement(el); + } + } + + // Finally switch the point indices of the surface elements + // to the newly added ones + PrintMessage(3, "Transferring boundary layer surface elements to new vertex references..."); + + for(SurfaceElementIndex sei : Range(nse)) + { + auto& sel = mesh[sei]; + if((blp.outside && !blp.surfid.Contains(sel.GetIndex())) || + (!blp.outside && blp.surfid.Contains(sel.GetIndex()))) + { + for(auto& pnum : sel.PNums()) + // Check (Doublecheck) if the corresponding point has a // copy available for remapping - if (mapto.Get(sel.PNum(j))) - { - // Map the surface elements to the new points - sel.PNum(j) = mapto.Get(sel.PNum(j)); - } - } - } - } - for (int i = 1; i <= ne; i++) - { - Element & el = mesh.VolumeElement(i); - if(el.GetIndex() != blp.bulk_matnr) + if(mapto[pnum].IsValid()) + // Map the surface elements to the new points + pnum = mapto[pnum]; + } + } + + if(blp.outside) + for(ElementIndex ei : Range(ne)) { - for (int j = 1; j <= el.GetNP(); j++) - { - // Check (Doublecheck) if the corresponding point has a - // copy available for remapping - if (mapto.Get(el.PNum(j))) - { - // Map the surface elements to the new points - el.PNum(j) = mapto.Get(el.PNum(j)); - } - } + auto& el = mesh[ei]; + for(auto& pnum : el.PNums()) + // Check (Doublecheck) if the corresponding point has a + // copy available for remapping + if(mapto[pnum].IsValid()) + // Map the surface elements to the new points + pnum = mapto[pnum]; } - } + // Lock all the prism points so that the rest of the mesh can be + // optimised without invalidating the entire mesh + // for (PointIndex pi = mesh.Points().Begin(); pi < mesh.Points().End(); pi++) + for (PointIndex pi = 1; pi <= np; pi++) + if(bndnodes.Test(pi)) mesh.AddLockedPoint(pi); + // Now, actually pull back the old surface points to create + // the actual boundary layers + PrintMessage(3, "Moving and optimising boundary layer points..."); - - // Lock all the prism points so that the rest of the mesh can be - // optimised without invalidating the entire mesh - // for (PointIndex pi = mesh.Points().Begin(); pi < mesh.Points().End(); pi++) - for (PointIndex pi : mesh.Points().Range()) - { - if(bndnodes.Test(pi)) mesh.AddLockedPoint(pi); - } + for (PointIndex i = 1; i <= np; i++) + { + if(bndnodes.Test(i)) + { + MeshPoint pointtomove; - // Now, actually pull back the old surface points to create - // the actual boundary layers - cout << "Moving and optimising boundary layer points...." << endl; - - for (int i = 1; i <= np; i++) - { - NgArray vertelems; + pointtomove = mesh.Point(i); + mesh.Point(i).SetPoint(pointtomove + layerht * growthvectors[i]); + } + } + mesh.Compress(); + } - if(bndnodes.Test(i)) - { - MeshPoint pointtomove; - - pointtomove = mesh.Point(i); - - if(layer == prismlayers) - { - mesh.Point(i).SetPoint(pointtomove + layerht * growthvectors.Elem(i)); - - meshtopo.GetVertexElements(i,vertelems); - - for(int j = 1; j <= vertelems.Size(); j++) - { - // double sfact = 0.9; - Element volel = mesh.VolumeElement(vertelems.Elem(j)); - if(((volel.GetType() == TET) || (volel.GetType() == TET10)) && (!volel.IsDeleted())) - { - //while((volel.Volume(mesh.Points()) <= 0.0) && (sfact >= 0.0)) - //{ - // mesh.Point(i).SetPoint(pointtomove + (sfact * layerht * growthvectors.Elem(i))); - // mesh.ImproveMesh(); - - // // Try to move the point back by one step but - // // if the volume drops to below zero, double back - // mesh.Point(i).SetPoint(pointtomove + ((sfact + 0.1) * layerht * growthvectors.Elem(i))); - // if(volel.Volume(mesh.Points()) <= 0.0) - // { - // mesh.Point(i).SetPoint(pointtomove + (sfact * layerht * growthvectors.Elem(i))); - // } - // sfact -= 0.1; - //} - volel.Delete(); - } - } - } - else - { - mesh.Point(i).SetPoint(pointtomove + layerht * growthvectors.Elem(i)); - } - } - } - mesh.Compress(); - } - - // Optimise the tet part of the volume mesh after all the modifications - // to the system are completed - //OptimizeVolume(mparam,mesh); + for(int i=1; i <= mesh.GetNFD(); i++) + { + auto& fd = mesh.GetFaceDescriptor(i); + if(blp.surfid.Contains(fd.SurfNr())) + { + if(blp.outside) + fd.SetDomainOut(blp.new_matnrs[0]); + else + fd.SetDomainIn(blp.new_matnrs[0]); + } + } - cout << "New NP: " << mesh.GetNP() << endl; - cout << "Num of Quads: " << numquads << endl; - cout << "Num of Prisms: " << numprisms << endl; - cout << "Boundary Layer Generation....Done!" << endl; - - dbg.close(); + PrintMessage(3, "New NP: ", mesh.GetNP()); + PrintMessage(3, "Num of Quads: ", numquads); + PrintMessage(3, "Num of Prisms: ", numprisms); + PrintMessage(1, "Boundary Layer Generation....Done!"); } - } - diff --git a/libsrc/meshing/boundarylayer.hpp b/libsrc/meshing/boundarylayer.hpp index a174a55a..4c7d62a8 100644 --- a/libsrc/meshing/boundarylayer.hpp +++ b/libsrc/meshing/boundarylayer.hpp @@ -12,18 +12,15 @@ class BoundaryLayerParameters { public: // parameters by Philippose .. - NgArray surfid; - NgArray heights; - NgArray new_matnrs; - int prismlayers = 1; - int bulk_matnr = 1; - int new_matnr = 1; - double hfirst = 0.01; - double growthfactor = 1; - bool optimize = true; + Array surfid; + Array heights; + Array new_matnrs; + bool outside = false; // set the boundary layer on the outside + bool grow_edges = false; }; -DLL_HEADER extern void GenerateBoundaryLayer (Mesh & mesh, BoundaryLayerParameters & blp); +DLL_HEADER void GenerateBoundaryLayer (Mesh & mesh, + const BoundaryLayerParameters & blp); #endif diff --git a/libsrc/meshing/python_mesh.cpp b/libsrc/meshing/python_mesh.cpp index 7e1f4821..05e0edbb 100644 --- a/libsrc/meshing/python_mesh.cpp +++ b/libsrc/meshing/python_mesh.cpp @@ -1,5 +1,7 @@ #ifdef NG_PYTHON +#include + #include <../general/ngpython.hpp> #include #include "python_mesh.hpp" @@ -885,12 +887,13 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m) meshingparameter_description.c_str(), py::call_guard()) - .def ("OptimizeVolumeMesh", [](Mesh & self) + .def ("OptimizeVolumeMesh", [](Mesh & self, MeshingParameters* pars) { MeshingParameters mp; - mp.optsteps3d = 5; + if(pars) mp = *pars; + else mp.optsteps3d = 5; OptimizeVolume (mp, self); - },py::call_guard()) + }, py::arg("mp"), py::call_guard()) .def ("OptimizeMesh2d", [](Mesh & self) { @@ -929,63 +932,87 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m) .def ("BuildSearchTree", &Mesh::BuildElementSearchTree,py::call_guard()) - .def ("BoundaryLayer", FunctionPointer - ([](Mesh & self, int bc, py::list thicknesses, int volnr, py::list materials) + .def ("BoundaryLayer", [](Mesh & self, variant boundary, + variant thickness, + variant material, + variant domain, bool outside, + bool grow_edges) { - int n = py::len(thicknesses); BoundaryLayerParameters blp; - - for (int i = 1; i <= self.GetNFD(); i++) - if (self.GetFaceDescriptor(i).BCProperty() == bc) - blp.surfid.Append (i); - - cout << "add layer at surfaces: " << blp.surfid << endl; - - blp.prismlayers = n; - blp.growthfactor = 1.0; - - // find max domain nr - int maxind = 0; - for (ElementIndex ei = 0; ei < self.GetNE(); ei++) - maxind = max (maxind, self[ei].GetIndex()); - cout << "maxind = " << maxind << endl; - for ( int i=0; i(&boundary); bc) { - blp.heights.Append( py::extract(thicknesses[i])()) ; - blp.new_matnrs.Append( maxind+1+i ); - self.SetMaterial (maxind+1+i, py::extract(materials[i])().c_str()); + for (int i = 1; i <= self.GetNFD(); i++) + if(self.GetFaceDescriptor(i).BCProperty() == *bc) + blp.surfid.Append (i); } - blp.bulk_matnr = volnr; + else + { + regex pattern(std::get(boundary)); + for(int i = 1; i<=self.GetNFD(); i++) + if(regex_match(self.GetFaceDescriptor(i).GetBCName(), pattern)) + blp.surfid.Append(i); + } + + if(double* pthickness = get_if(&thickness); pthickness) + { + blp.heights.Append(*pthickness); + } + else + { + auto thicknesses = get(thickness); + for(auto val : thicknesses) + blp.heights.Append(val.cast()); + } + + auto prismlayers = blp.heights.Size(); + auto first_new_mat = self.GetNDomains() + 1; + for(auto i : Range(prismlayers)) + blp.new_matnrs.Append(first_new_mat + i); + if(string* pmaterial = get_if(&material); pmaterial) + { + for(auto i : Range(prismlayers)) + self.SetMaterial(first_new_mat + i, *pmaterial); + } + else + { + auto materials = get(material); + if(py::len(materials) != prismlayers) + throw Exception("Length of thicknesses and materials must be same!"); + for(auto i : Range(prismlayers)) + self.SetMaterial(first_new_mat + i, materials[i].cast()); + } + + blp.outside = outside; + blp.grow_edges = grow_edges; + GenerateBoundaryLayer (self, blp); - } - )) + }, py::arg("boundary"), py::arg("thickness"), py::arg("material"), + py::arg("domain") = 1, py::arg("outside") = false, + py::arg("grow_edges") = false, R"delimiter( +Add boundary layer to mesh. - .def ("BoundaryLayer", FunctionPointer - ([](Mesh & self, int bc, double thickness, int volnr, string material) - { - BoundaryLayerParameters blp; +Parameters +---------- - for (int i = 1; i <= self.GetNFD(); i++) - if (self.GetFaceDescriptor(i).BCProperty() == bc) - blp.surfid.Append (i); +boundary : string or int + Boundary name or number. - cout << "add layer at surfaces: " << blp.surfid << endl; +thickness : float or List[float] + Thickness of boundary layer(s). - blp.prismlayers = 1; - blp.hfirst = thickness; - blp.growthfactor = 1.0; +material : str or List[str] + Material name of boundary layer(s). - // find max domain nr - int maxind = 0; - for (ElementIndex ei = 0; ei < self.GetNE(); ei++) - maxind = max (maxind, self[ei].GetIndex()); - cout << "maxind = " << maxind << endl; - self.SetMaterial (maxind+1, material.c_str()); - blp.new_matnr = maxind+1; - blp.bulk_matnr = volnr; - GenerateBoundaryLayer (self, blp); - } - )) +domain : string or int + Add layer into domain specified by name or number. + +outside : bool = False + If true add the layer on the outside + +grow_edges : bool = False + Grow boundary layer over edges. + +)delimiter") .def ("EnableTable", [] (Mesh & self, string name, bool set) { diff --git a/libsrc/meshing/topology.hpp b/libsrc/meshing/topology.hpp index 558646a2..8335f101 100644 --- a/libsrc/meshing/topology.hpp +++ b/libsrc/meshing/topology.hpp @@ -166,7 +166,7 @@ public: { return vert2element[vnr]; } void GetVertexSurfaceElements( int vnr, NgArray& elements ) const; - NgFlatArray GetVertexSurfaceElements (int vnr) const + NgFlatArray GetVertexSurfaceElements(PointIndex vnr) const { return vert2surfelement[vnr]; } NgFlatArray GetVertexSegments (int vnr) const diff --git a/ng/ngpkg.cpp b/ng/ngpkg.cpp index afd4d0e1..52279b19 100644 --- a/ng/ngpkg.cpp +++ b/ng/ngpkg.cpp @@ -1155,7 +1155,7 @@ namespace netgen // Use an array to support creation of boundary // layers for multiple surfaces in the future... - NgArray surfid; + Array surfid; int surfinp = 0; int prismlayers = 1; double hfirst = 0.01; @@ -1172,8 +1172,8 @@ namespace netgen cout << "Number of surfaces entered = " << surfid.Size() << endl; cout << "Selected surfaces are:" << endl; - for(int i = 1; i <= surfid.Size(); i++) - cout << "Surface " << i << ": " << surfid.Elem(i) << endl; + for(auto i : Range(surfid)) + cout << "Surface " << i << ": " << surfid[i] << endl; cout << endl << "Enter number of prism layers: "; cin >> prismlayers; @@ -1189,9 +1189,14 @@ namespace netgen BoundaryLayerParameters blp; blp.surfid = surfid; - blp.prismlayers = prismlayers; - blp.hfirst = blp.hfirst; - blp.growthfactor = growthfactor; + for(auto i : Range(prismlayers)) + { + auto layer = i+1; + if(growthfactor == 1) + blp.heights.Append(layer * hfirst); + else + blp.heights.Append(hfirst * (pow(growthfactor, (layer+1))-1)/(growthfactor-1)); + } GenerateBoundaryLayer (*mesh, blp); return TCL_OK; } diff --git a/tests/pytest/test_boundarylayer.py b/tests/pytest/test_boundarylayer.py new file mode 100644 index 00000000..9be268c0 --- /dev/null +++ b/tests/pytest/test_boundarylayer.py @@ -0,0 +1,17 @@ + +import pytest +from netgen.csg import * + +@pytest.mark.parametrize("outside", [True, False]) +def test_boundarylayer(outside): + mesh = unit_cube.GenerateMesh(maxh=0.3) + ne_before = mesh.ne + nse_in_layer = 0 + layer_surfacenames = ["right", "top"] + for el in mesh.Elements2D(): + if mesh.GetBCName(el.index-1) in layer_surfacenames: + nse_in_layer += 1 + mesh.BoundaryLayer("|".join(layer_surfacenames), [0.01, 0.02], "layer", outside=outside, grow_edges=True) + assert mesh.ne == ne_before + 2 * nse_in_layer + + From 16ae2df9803925d3177bcd6cd794b5e7959fe1c7 Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Mon, 20 Apr 2020 10:09:26 +0200 Subject: [PATCH 027/384] std::get for variant not available on mac os < 10.14 --- libsrc/meshing/python_mesh.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libsrc/meshing/python_mesh.cpp b/libsrc/meshing/python_mesh.cpp index 05e0edbb..3dfc36d3 100644 --- a/libsrc/meshing/python_mesh.cpp +++ b/libsrc/meshing/python_mesh.cpp @@ -939,7 +939,7 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m) bool grow_edges) { BoundaryLayerParameters blp; - if(int* bc = std::get_if(&boundary); bc) + if(int* bc = get_if(&boundary); bc) { for (int i = 1; i <= self.GetNFD(); i++) if(self.GetFaceDescriptor(i).BCProperty() == *bc) @@ -947,7 +947,7 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m) } else { - regex pattern(std::get(boundary)); + regex pattern(*get_if(&boundary)); for(int i = 1; i<=self.GetNFD(); i++) if(regex_match(self.GetFaceDescriptor(i).GetBCName(), pattern)) blp.surfid.Append(i); @@ -959,7 +959,7 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m) } else { - auto thicknesses = get(thickness); + auto thicknesses = *get_if(&thickness); for(auto val : thicknesses) blp.heights.Append(val.cast()); } @@ -975,7 +975,7 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m) } else { - auto materials = get(material); + auto materials = *get_if(&material); if(py::len(materials) != prismlayers) throw Exception("Length of thicknesses and materials must be same!"); for(auto i : Range(prismlayers)) From 27baa178d250d6e59ec03d3a611acd56501bf7cb Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Mon, 20 Apr 2020 10:13:04 +0200 Subject: [PATCH 028/384] fix new clang warning and add helper function --- libsrc/core/utils.hpp | 4 ++++ libsrc/occ/occpkg.cpp | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/libsrc/core/utils.hpp b/libsrc/core/utils.hpp index 65db4fff..8dd5c531 100644 --- a/libsrc/core/utils.hpp +++ b/libsrc/core/utils.hpp @@ -23,6 +23,10 @@ namespace ngcore NGCORE_API std::string Demangle(const char* typeinfo); + template + NGCORE_API std::string GetName(const T& obj) + { return Demangle(typeid(obj).name()); } + #if defined(__GNUC__) inline bool likely (bool x) { return bool(__builtin_expect(long(x), 1L)); } inline bool unlikely (bool x) { return bool(__builtin_expect(long(x), 0L)); } diff --git a/libsrc/occ/occpkg.cpp b/libsrc/occ/occpkg.cpp index a4f019a7..62d0fe0b 100644 --- a/libsrc/occ/occpkg.cpp +++ b/libsrc/occ/occpkg.cpp @@ -519,7 +519,8 @@ namespace netgen stringstream str; occgeometry->GetTopologyTree (str); - char* cstr = (char*)str.str().c_str(); + auto txt = str.str(); + char* cstr = (char*) txt.c_str(); (*testout) << cstr << endl; From 9af476c353bc5d41901e88fee2866ec84fbcf825 Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Mon, 20 Apr 2020 10:26:17 +0200 Subject: [PATCH 029/384] template shouldn't have NGCORE_API --- libsrc/core/utils.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsrc/core/utils.hpp b/libsrc/core/utils.hpp index 8dd5c531..81b0073f 100644 --- a/libsrc/core/utils.hpp +++ b/libsrc/core/utils.hpp @@ -24,7 +24,7 @@ namespace ngcore NGCORE_API std::string Demangle(const char* typeinfo); template - NGCORE_API std::string GetName(const T& obj) + std::string GetName(const T& obj) { return Demangle(typeid(obj).name()); } #if defined(__GNUC__) From d752ada2bdf0e65bb55baef6ec9d276829aab90a Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Thu, 23 Apr 2020 15:44:32 +0200 Subject: [PATCH 030/384] improve functionality of boundarylayer --- libsrc/meshing/boundarylayer.cpp | 369 +++++++++++++++++++++-------- libsrc/meshing/boundarylayer.hpp | 1 + libsrc/meshing/python_mesh.cpp | 41 +++- tests/pytest/test_boundarylayer.py | 26 +- 4 files changed, 321 insertions(+), 116 deletions(-) diff --git a/libsrc/meshing/boundarylayer.cpp b/libsrc/meshing/boundarylayer.cpp index 0d61d4cc..4b970070 100644 --- a/libsrc/meshing/boundarylayer.cpp +++ b/libsrc/meshing/boundarylayer.cpp @@ -103,7 +103,7 @@ namespace netgen function, in order to calculate the effective direction in which the prismatic layer should grow */ - Vec<3> GetSurfaceNormal(Mesh & mesh, const Element2d & el) + inline Vec<3> GetSurfaceNormal(Mesh & mesh, const Element2d & el) { auto v0 = mesh[el[0]]; auto v1 = mesh[el[1]]; @@ -115,12 +115,9 @@ namespace netgen return normal; } - - - - /* Philippose Rajan - 11 June 2009 + modified by Christopher Lackner Apr 2020 Added an initial experimental function for generating prismatic boundary layers on @@ -149,10 +146,38 @@ namespace netgen PrintMessage(3, "Old NP: ", mesh.GetNP()); PrintMessage(3, "Old NSE: ",mesh.GetNSE()); + map, int> domains_to_surf_index; + map, int> pi_to_edgenr; + + map last_layer_surface_index_map; + int max_surface_index = mesh.GetNFD(); + + int max_edge_nr = -1; + for(const auto& seg : mesh.LineSegments()) + if(seg.edgenr > max_edge_nr) + max_edge_nr = seg.edgenr; + for(int layer = blp.heights.Size(); layer >= 1; layer--) { PrintMessage(3, "Generating layer: ", layer); + auto map_surface_index = [&](auto si) + { + if(last_layer_surface_index_map.find(si) == last_layer_surface_index_map.end()) + { + last_layer_surface_index_map[si] = ++max_surface_index; + auto& old_fd = mesh.GetFaceDescriptor(si); + int domout = blp.outside ? old_fd.DomainOut() : blp.new_matnrs[layer-1]; + int domin = blp.outside ? blp.new_matnrs[layer-1] : old_fd.DomainIn(); + FaceDescriptor fd(max_surface_index-1, + domin, domout, -1); + fd.SetBCProperty(max_surface_index); + mesh.AddFaceDescriptor(fd); + return max_surface_index; + } + return last_layer_surface_index_map[si]; + }; + mesh.UpdateTopology(); auto& meshtopo = mesh.GetTopology(); @@ -213,7 +238,7 @@ namespace netgen } if (!blp.grow_edges) - for(const auto& sel : mesh.SurfaceElements()) + for(const auto& sel : mesh.LineSegments()) { bndnodes.Clear(sel[0]); bndnodes.Clear(sel[1]); @@ -241,8 +266,6 @@ namespace netgen } growthvectors[pi] += veci; } - // growthvectors[pi].Normalize(); - // growthvectors[pi] *= -1.0; } else { @@ -251,7 +274,6 @@ namespace netgen } } - // Add quad surface elements at edges for surfaces which // don't have boundary layers @@ -271,13 +293,15 @@ namespace netgen // Only go in if the segment is still active, and if both its // surface index is part of the "hit-list" - if(segsel.Test(sei) && blp.surfid.Contains(mesh[sei].si)) + if(segsel.Test(sei)) + { + if(blp.surfid.Contains(mesh[sei].si)) { // clear the bit to indicate that this segment has been processed segsel.Clear(sei); // Find matching segment pair on other surface - for (SegmentIndex sej = 0; sej < nseg; sej++) + for(SegmentIndex sej = 0; sej < nseg; sej++) { PointIndex segpair_p1 = mesh[sej][1]; PointIndex segpair_p2 = mesh[sej][0]; @@ -300,34 +324,20 @@ namespace netgen auto pnt2_elems = meshtopo.GetVertexSurfaceElements(segpair_p2); for(auto pnt1_sei : pnt1_elems) - { - const auto& pnt1_sel = mesh[pnt1_sei]; + if(mesh[pnt1_sei].GetIndex() == mesh[sej].si) for(auto pnt2_sei : pnt2_elems) - { - const Element2d & pnt2_sel = mesh.SurfaceElement(pnt2_sei); - if((pnt1_sel.GetIndex() == mesh[sej].si) - && (pnt2_sel.GetIndex() == mesh[sej].si) - && (pnt1_sei == pnt2_sei)) - { - pnt_commelem = pnt1_sei; - } - } - } + if(pnt1_sei == pnt2_sei) + pnt_commelem = pnt1_sei; - const Element2d & commsel = mesh.SurfaceElement(pnt_commelem); + if(IsInvalid(pnt_commelem)) + throw Exception("Couldn't find element on other side for " + ToString(segpair_p1) + " to " + ToString(segpair_p2)); + + const auto& commsel = mesh[pnt_commelem]; auto surfelem_vect = GetSurfaceNormal(mesh, commsel); if(blp.outside) surfelem_vect *= -1; double surfangle = Angle(growthvectors[segpair_p1],surfelem_vect); - // remap the segments to the new points - if(!blp.outside) - { - mesh[sei][0] = mapto[seg_p1]; - mesh[sei][1] = mapto[seg_p2]; - mesh[sej][1] = mapto[seg_p1]; - mesh[sej][0] = mapto[seg_p2]; - } if((surfangle < (90 + angleThreshold) * 3.141592 / 180.0) && (surfangle > (90 - angleThreshold) * 3.141592 / 180.0)) @@ -342,109 +352,256 @@ namespace netgen Element2d sel(QUAD); if(blp.outside) Swap(seg_p1, seg_p2); - sel.PNum(4) = mapto[seg_p1]; - sel.PNum(3) = mapto[seg_p2]; - sel.PNum(2) = seg_p2; - sel.PNum(1) = seg_p1; - sel.SetIndex(mesh[sej].si); + sel[0] = seg_p1; + sel[1] = seg_p2; + sel[2] = mapto[seg_p2]; + sel[3] = mapto[seg_p1]; + auto domains = make_tuple(commsel.GetIndex(), blp.new_matnrs[layer-1], mesh.GetFaceDescriptor(commsel.GetIndex()).DomainOut()); + + if(domains_to_surf_index.find(domains) == domains_to_surf_index.end()) + { + domains_to_surf_index[domains] = ++max_surface_index; + domains_to_surf_index[make_tuple(max_surface_index, get<1>(domains), get<2>(domains))] = max_surface_index; + FaceDescriptor fd(max_surface_index-1, + get<1>(domains), + get<2>(domains), + -1); + fd.SetBCProperty(max_surface_index); + mesh.AddFaceDescriptor(fd); + mesh.SetBCName(max_surface_index-1, + mesh.GetBCName(get<0>(domains)-1)); + } + auto new_index = domains_to_surf_index[domains]; + sel.SetIndex(new_index); mesh.AddSurfaceElement(sel); numquads++; + + // Add segments + Segment seg_1, seg_2; + seg_1[0] = mapto[seg_p1]; + seg_1[1] = seg_p1; + seg_2[0] = seg_p2; + seg_2[1] = mapto[seg_p2]; + auto points = make_tuple(seg_p1, mapto[seg_p1]); + if(pi_to_edgenr.find(points) == pi_to_edgenr.end()) + pi_to_edgenr[points] = ++max_edge_nr; + seg_1.edgenr = pi_to_edgenr[points]; + seg_1[2] = PointIndex::INVALID; + seg_1.si = new_index; + mesh.AddSegment(seg_1); + + points = make_tuple(seg_p2, mapto[seg_p2]); + if(pi_to_edgenr.find(points) == pi_to_edgenr.end()) + pi_to_edgenr[points] = ++max_edge_nr; + + seg_2[2] = PointIndex::INVALID; + seg_2.edgenr = pi_to_edgenr[points]; + seg_2.si = new_index; + mesh.AddSegment(seg_2); + mesh[sej].si = new_index; } else { - for (int k = 0; k < pnt1_elems.Size(); k++) + for(auto pnt1_ei : pnt1_elems) { - Element2d & pnt_sel = mesh.SurfaceElement(pnt1_elems[k]); + auto& pnt_sel = mesh[pnt1_ei]; if(pnt_sel.GetIndex() == mesh[sej].si) { - for(int l = 0; l < pnt_sel.GetNP(); l++) + for(auto& pi : pnt_sel.PNums()) { - if(pnt_sel[l] == segpair_p1) - pnt_sel[l] = mapto[seg_p1]; - else if (pnt_sel[l] == segpair_p2) - pnt_sel[l] = mapto[seg_p2]; + if(pi == segpair_p1) + pi = mapto[seg_p1]; + else if(pi == segpair_p2) + pi = mapto[seg_p2]; } } } - for (int k = 0; k < pnt2_elems.Size(); k++) + for(auto sk : pnt2_elems) { - Element2d & pnt_sel = mesh.SurfaceElement(pnt2_elems[k]); + auto& pnt_sel = mesh[sk]; if(pnt_sel.GetIndex() == mesh[sej].si) { - for(int l = 0; l < pnt_sel.GetNP(); l++) + for(auto& p : pnt_sel.PNums()) { - if(pnt_sel[l] == segpair_p1) - pnt_sel[l] = mapto[seg_p1]; - else if (pnt_sel[l] == segpair_p2) - pnt_sel[l] = mapto[seg_p2]; + if(p == segpair_p1) + p = mapto[seg_p1]; + else if (p == segpair_p2) + p = mapto[seg_p2]; } } } } - // } } - else + + // in last layer insert new segments + if(layer == blp.heights.Size()) { - // If the code comes here, it indicates that we are at - // a line segment pair which is at the intersection - // of two surfaces, both of which have to grow boundary - // layers.... here too, remapping the segments to the - // new points is required - mesh[sei][0] = mapto[seg_p1]; - mesh[sei][1] = mapto[seg_p2]; - mesh[sej][1] = mapto[seg_p1]; - mesh[sej][0] = mapto[seg_p2]; + Segment s1 = mesh[sei]; + Segment s2 = mesh[sej]; + s1.edgenr = ++max_edge_nr; + s2.edgenr = max_edge_nr; + bool create_it = true; + if(blp.surfid.Contains(mesh[sej].si)) + { + if(last_layer_surface_index_map.find(s1.si) != last_layer_surface_index_map.end() && + last_layer_surface_index_map.find(s2.si) != last_layer_surface_index_map.end()) + // edge already mapped + create_it = false; + s2.si = map_surface_index(s2.si); + } + else + { + s2.si = domains_to_surf_index[make_tuple(s2.si, + blp.new_matnrs[layer-1], mesh.GetFaceDescriptor(s2.si).DomainOut())]; + } + s1.si = map_surface_index(s1.si); + if(create_it) + { + mesh.AddSegment(s1); + mesh.AddSegment(s2); + } } + + // remap the segments to the new points + mesh[sei][0] = mapto[mesh[sei][0]]; + mesh[sei][1] = mapto[mesh[sei][1]]; + mesh[sej][1] = mapto[mesh[sej][1]]; + mesh[sej][0] = mapto[mesh[sej][0]]; + } } } + else + { + // check if it doesn't contain the other edge as well + // and if it doesn't contain both mark them as done and + // if necessary map them + for(SegmentIndex sej = 0; sej surfid; Array heights; Array new_matnrs; + BitArray domains; bool outside = false; // set the boundary layer on the outside bool grow_edges = false; }; diff --git a/libsrc/meshing/python_mesh.cpp b/libsrc/meshing/python_mesh.cpp index 3dfc36d3..fdfb2c40 100644 --- a/libsrc/meshing/python_mesh.cpp +++ b/libsrc/meshing/python_mesh.cpp @@ -966,12 +966,12 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m) auto prismlayers = blp.heights.Size(); auto first_new_mat = self.GetNDomains() + 1; - for(auto i : Range(prismlayers)) - blp.new_matnrs.Append(first_new_mat + i); + auto max_dom_nr = first_new_mat; if(string* pmaterial = get_if(&material); pmaterial) { + self.SetMaterial(first_new_mat, *pmaterial); for(auto i : Range(prismlayers)) - self.SetMaterial(first_new_mat + i, *pmaterial); + blp.new_matnrs.Append(first_new_mat); } else { @@ -979,16 +979,41 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m) if(py::len(materials) != prismlayers) throw Exception("Length of thicknesses and materials must be same!"); for(auto i : Range(prismlayers)) - self.SetMaterial(first_new_mat + i, materials[i].cast()); + { + self.SetMaterial(first_new_mat+i, materials[i].cast()); + blp.new_matnrs.Append(first_new_mat + i); + } + max_dom_nr += prismlayers-1; } + blp.domains.SetSize(max_dom_nr + 1); // one based + blp.domains.Clear(); + if(string* pdomain = get_if(&domain); pdomain) + { + regex pattern(*pdomain); + for(auto i : Range(1, first_new_mat)) + if(regex_match(self.GetMaterial(i), pattern)) + blp.domains.SetBit(i); + } + else + { + auto idomain = *get_if(&domain); + blp.domains.SetBit(idomain); + } + // bits for new domains must be set + if(!outside) + for(auto i : Range(first_new_mat, max_dom_nr+1)) + blp.domains.SetBit(i); + blp.outside = outside; blp.grow_edges = grow_edges; GenerateBoundaryLayer (self, blp); + self.UpdateTopology(); }, py::arg("boundary"), py::arg("thickness"), py::arg("material"), - py::arg("domain") = 1, py::arg("outside") = false, - py::arg("grow_edges") = false, R"delimiter( + py::arg("domains") = ".*", py::arg("outside") = false, + py::arg("grow_edges") = false, + R"delimiter( Add boundary layer to mesh. Parameters @@ -1003,8 +1028,8 @@ thickness : float or List[float] material : str or List[str] Material name of boundary layer(s). -domain : string or int - Add layer into domain specified by name or number. +domain : str or int + Regexp for domain boundarylayer is going into. outside : bool = False If true add the layer on the outside diff --git a/tests/pytest/test_boundarylayer.py b/tests/pytest/test_boundarylayer.py index 9be268c0..1733323d 100644 --- a/tests/pytest/test_boundarylayer.py +++ b/tests/pytest/test_boundarylayer.py @@ -2,16 +2,30 @@ import pytest from netgen.csg import * +def GetNSurfaceElements(mesh, boundary): + nse_in_layer = 0 + for el in mesh.Elements2D(): + print(el.index) + if mesh.GetBCName(el.index-1) == boundary: + nse_in_layer += 1 + return nse_in_layer + @pytest.mark.parametrize("outside", [True, False]) -def test_boundarylayer(outside): +def test_boundarylayer(outside, capfd): mesh = unit_cube.GenerateMesh(maxh=0.3) ne_before = mesh.ne - nse_in_layer = 0 layer_surfacenames = ["right", "top"] - for el in mesh.Elements2D(): - if mesh.GetBCName(el.index-1) in layer_surfacenames: - nse_in_layer += 1 mesh.BoundaryLayer("|".join(layer_surfacenames), [0.01, 0.02], "layer", outside=outside, grow_edges=True) - assert mesh.ne == ne_before + 2 * nse_in_layer + should_ne = ne_before + 2 * sum([GetNSurfaceElements(mesh, surf) for surf in layer_surfacenames]) + assert mesh.ne == should_ne + capture = capfd.readouterr() + assert not "elements are not matching" in capture.out + + for side in ["front"]: + mesh.BoundaryLayer(side, [0.001], "layer", outside=outside, grow_edges=True) + should_ne += GetNSurfaceElements(mesh, side) + assert mesh.ne == should_ne + capture = capfd.readouterr() + assert not "elements are not matching" in capture.out From 97baba04a0c1942a080d2cf9470a68c94d576c77 Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Sat, 25 Apr 2020 11:15:36 +0200 Subject: [PATCH 031/384] fix growthvector direction --- libsrc/meshing/boundarylayer.cpp | 188 ++++++++++--------------------- 1 file changed, 60 insertions(+), 128 deletions(-) diff --git a/libsrc/meshing/boundarylayer.cpp b/libsrc/meshing/boundarylayer.cpp index 4b970070..ae7c7a30 100644 --- a/libsrc/meshing/boundarylayer.cpp +++ b/libsrc/meshing/boundarylayer.cpp @@ -132,16 +132,6 @@ namespace netgen */ void GenerateBoundaryLayer (Mesh & mesh, const BoundaryLayerParameters & blp) { - // Angle between a surface element and a growth-vector below which - // a prism is project onto that surface as a quad - // (in degrees) - double angleThreshold = 5.0; - - // Monitor and print out the number of prism and quad elements - // added to the mesh - int numprisms = 0; - int numquads = 0; - PrintMessage(1, "Generating boundary layer..."); PrintMessage(3, "Old NP: ", mesh.GetNP()); PrintMessage(3, "Old NSE: ",mesh.GetNSE()); @@ -205,7 +195,7 @@ namespace netgen // Growth vectors for the prismatic layer based on // the effective surface normal at a given point Array, PointIndex> growthvectors(np); - Array>, PointIndex> all_growthvectors(np); + growthvectors = 0.; // Bit array to identify all the points belonging // to the surface of interest @@ -221,19 +211,26 @@ namespace netgen for(const auto& sel : mesh.SurfaceElements()) if (blp.surfid.Contains(sel.GetIndex())) { - auto normal = GetSurfaceNormal(mesh,sel); + auto n2 = GetSurfaceNormal(mesh,sel); if(!blp.outside) - normal *= -1; - for(int j : Range(sel.PNums())) + n2 *= -1; + for(auto pi : sel.PNums()) { // Set the bitarray to indicate that the // point is part of the required set - bndnodes.SetBit(sel[j]); + bndnodes.SetBit(pi); // Add the surface normal to the already existent one // (This gives the effective normal direction at corners // and curved areas) - all_growthvectors[sel[j]].Append(normal); + + auto& n1 = growthvectors[pi]; + if(n1.Length() == 0) { n1 = n2; continue; } + auto n1n2 = n1 * n2; + auto n1n1 = n1 * n1; + auto n2n2 = n2 * n2; + if(n2n2 - n1n2*n1n2/n1n1 == 0) { n1 = n2; continue; } + n1 += (n2n2 - n1n2)/(n2n2 - n1n2*n1n2/n1n1) * (n2 - n1n2/n1n1 * n1); } } @@ -253,25 +250,9 @@ namespace netgen for (PointIndex pi = 1; pi <= np; pi++) { if (bndnodes.Test(pi)) - { - mapto[pi] = mesh.AddPoint(mesh[pi]); - growthvectors[pi] = all_growthvectors[pi][0]; - for(int i = 1; i < all_growthvectors[pi].Size(); i++) - { - auto& veci = all_growthvectors[pi][i]; - for(auto j : Range(i)) - { - auto& vecj = all_growthvectors[pi][j]; - veci -= 1./(vecj.Length()+1e-10) * (veci * vecj) * vecj; - } - growthvectors[pi] += veci; - } - } + mapto[pi] = mesh.AddPoint(mesh[pi]); else - { - mapto[pi].Invalidate(); - growthvectors[pi] = {0,0,0}; - } + mapto[pi].Invalidate(); } // Add quad surface elements at edges for surfaces which @@ -336,102 +317,55 @@ namespace netgen auto surfelem_vect = GetSurfaceNormal(mesh, commsel); if(blp.outside) surfelem_vect *= -1; + Element2d sel(QUAD); + if(blp.outside) + Swap(seg_p1, seg_p2); + sel[0] = seg_p1; + sel[1] = seg_p2; + sel[2] = mapto[seg_p2]; + sel[3] = mapto[seg_p1]; + auto domains = make_tuple(commsel.GetIndex(), blp.new_matnrs[layer-1], mesh.GetFaceDescriptor(commsel.GetIndex()).DomainOut()); - double surfangle = Angle(growthvectors[segpair_p1],surfelem_vect); - - if((surfangle < (90 + angleThreshold) * 3.141592 / 180.0) - && (surfangle > (90 - angleThreshold) * 3.141592 / 180.0)) + if(domains_to_surf_index.find(domains) == domains_to_surf_index.end()) { - // Since the surface is lower than the threshold, change the effective - // prism growth vector to match with the surface vector, so that - // the Quad which is created lies on the original surface - //growthvectors.Elem(segpair_p1) = surfelem_vect; - - // Add a quad element to account for the prism volume - // element which is going to be added - Element2d sel(QUAD); - if(blp.outside) - Swap(seg_p1, seg_p2); - sel[0] = seg_p1; - sel[1] = seg_p2; - sel[2] = mapto[seg_p2]; - sel[3] = mapto[seg_p1]; - auto domains = make_tuple(commsel.GetIndex(), blp.new_matnrs[layer-1], mesh.GetFaceDescriptor(commsel.GetIndex()).DomainOut()); - - if(domains_to_surf_index.find(domains) == domains_to_surf_index.end()) - { - domains_to_surf_index[domains] = ++max_surface_index; - domains_to_surf_index[make_tuple(max_surface_index, get<1>(domains), get<2>(domains))] = max_surface_index; - FaceDescriptor fd(max_surface_index-1, - get<1>(domains), - get<2>(domains), - -1); - fd.SetBCProperty(max_surface_index); - mesh.AddFaceDescriptor(fd); - mesh.SetBCName(max_surface_index-1, - mesh.GetBCName(get<0>(domains)-1)); - } - auto new_index = domains_to_surf_index[domains]; - sel.SetIndex(new_index); - mesh.AddSurfaceElement(sel); - numquads++; - - // Add segments - Segment seg_1, seg_2; - seg_1[0] = mapto[seg_p1]; - seg_1[1] = seg_p1; - seg_2[0] = seg_p2; - seg_2[1] = mapto[seg_p2]; - auto points = make_tuple(seg_p1, mapto[seg_p1]); - if(pi_to_edgenr.find(points) == pi_to_edgenr.end()) - pi_to_edgenr[points] = ++max_edge_nr; - seg_1.edgenr = pi_to_edgenr[points]; - seg_1[2] = PointIndex::INVALID; - seg_1.si = new_index; - mesh.AddSegment(seg_1); - - points = make_tuple(seg_p2, mapto[seg_p2]); - if(pi_to_edgenr.find(points) == pi_to_edgenr.end()) - pi_to_edgenr[points] = ++max_edge_nr; - - seg_2[2] = PointIndex::INVALID; - seg_2.edgenr = pi_to_edgenr[points]; - seg_2.si = new_index; - mesh.AddSegment(seg_2); - mesh[sej].si = new_index; + domains_to_surf_index[domains] = ++max_surface_index; + domains_to_surf_index[make_tuple(max_surface_index, get<1>(domains), get<2>(domains))] = max_surface_index; + FaceDescriptor fd(max_surface_index-1, + get<1>(domains), + get<2>(domains), + -1); + fd.SetBCProperty(max_surface_index); + mesh.AddFaceDescriptor(fd); + mesh.SetBCName(max_surface_index-1, + mesh.GetBCName(get<0>(domains)-1)); } - else - { - for(auto pnt1_ei : pnt1_elems) - { - auto& pnt_sel = mesh[pnt1_ei]; - if(pnt_sel.GetIndex() == mesh[sej].si) - { - for(auto& pi : pnt_sel.PNums()) - { - if(pi == segpair_p1) - pi = mapto[seg_p1]; - else if(pi == segpair_p2) - pi = mapto[seg_p2]; - } - } - } + auto new_index = domains_to_surf_index[domains]; + sel.SetIndex(new_index); + mesh.AddSurfaceElement(sel); - for(auto sk : pnt2_elems) - { - auto& pnt_sel = mesh[sk]; - if(pnt_sel.GetIndex() == mesh[sej].si) - { - for(auto& p : pnt_sel.PNums()) - { - if(p == segpair_p1) - p = mapto[seg_p1]; - else if (p == segpair_p2) - p = mapto[seg_p2]; - } - } - } - } + // Add segments + Segment seg_1, seg_2; + seg_1[0] = mapto[seg_p1]; + seg_1[1] = seg_p1; + seg_2[0] = seg_p2; + seg_2[1] = mapto[seg_p2]; + auto points = make_tuple(seg_p1, mapto[seg_p1]); + if(pi_to_edgenr.find(points) == pi_to_edgenr.end()) + pi_to_edgenr[points] = ++max_edge_nr; + seg_1.edgenr = pi_to_edgenr[points]; + seg_1[2] = PointIndex::INVALID; + seg_1.si = new_index; + mesh.AddSegment(seg_1); + + points = make_tuple(seg_p2, mapto[seg_p2]); + if(pi_to_edgenr.find(points) == pi_to_edgenr.end()) + pi_to_edgenr[points] = ++max_edge_nr; + + seg_2[2] = PointIndex::INVALID; + seg_2.edgenr = pi_to_edgenr[points]; + seg_2.si = new_index; + mesh.AddSegment(seg_2); + mesh[sej].si = new_index; } // in last layer insert new segments @@ -680,8 +614,6 @@ namespace netgen } PrintMessage(3, "New NP: ", mesh.GetNP()); - PrintMessage(3, "Num of Quads: ", numquads); - PrintMessage(3, "Num of Prisms: ", numprisms); PrintMessage(1, "Boundary Layer Generation....Done!"); } } From 45a4b2c913c3b66b9e6cf373910a16878b06c162 Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Thu, 7 May 2020 10:03:00 +0200 Subject: [PATCH 032/384] pickle bitarrays --- libsrc/core/python_ngcore_export.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libsrc/core/python_ngcore_export.cpp b/libsrc/core/python_ngcore_export.cpp index 953dea59..1aaf12b0 100644 --- a/libsrc/core/python_ngcore_export.cpp +++ b/libsrc/core/python_ngcore_export.cpp @@ -30,6 +30,7 @@ PYBIND11_MODULE(pyngcore, m) // NOLINT if (a[i]) ba->SetBit(i); return ba; } ), py::arg("vec")) + .def(NGSPickle()) .def("__str__", &ToString) .def("__len__", &BitArray::Size) .def("__getitem__", [] (BitArray & self, int i) From 9ffb22c37fbd13ec6bb499a09a35ff8aa8daa51b Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Thu, 7 May 2020 10:52:09 +0200 Subject: [PATCH 033/384] fix archive of bitarray --- libsrc/core/bitarray.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsrc/core/bitarray.cpp b/libsrc/core/bitarray.cpp index daef541e..db9fc114 100644 --- a/libsrc/core/bitarray.cpp +++ b/libsrc/core/bitarray.cpp @@ -125,7 +125,7 @@ namespace ngcore } else { - int size; + size_t size; archive & size; ba.SetSize (size); ba.Clear(); From 97ba90ee40a5067cd50cc21092c625f1ca32fca7 Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Sun, 17 May 2020 20:24:22 +0200 Subject: [PATCH 034/384] DLL_HEADER for whole OCCGeometry --- libsrc/occ/occgeom.hpp | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/libsrc/occ/occgeom.hpp b/libsrc/occ/occgeom.hpp index a77cd7a4..372979ad 100644 --- a/libsrc/occ/occgeom.hpp +++ b/libsrc/occ/occgeom.hpp @@ -206,7 +206,7 @@ namespace netgen void Print (ostream & ost) const; }; - class OCCGeometry : public NetgenGeometry + class DLL_HEADER OCCGeometry : public NetgenGeometry { Point<3> center; OCCParameters occparam; @@ -276,7 +276,7 @@ namespace netgen void FinalizeMesh(Mesh& mesh) const override; - DLL_HEADER void Save (string filename) const override; + void Save (string filename) const override; void DoArchive(Archive& ar) override; @@ -298,7 +298,7 @@ namespace netgen const PointGeomInfo & gi2, Point<3> & newp, PointGeomInfo & newgi) const override; - DLL_HEADER void BuildFMap(); + void BuildFMap(); Box<3> GetBoundingBox() const { return boundingbox; } @@ -323,8 +323,8 @@ namespace netgen return OCCSurface (TopoDS::Face(fmap(surfi)), PLANESPACE); } - DLL_HEADER void CalcBoundingBox (); - DLL_HEADER void BuildVisualizationMesh (double deflection); + void CalcBoundingBox (); + void BuildVisualizationMesh (double deflection); void RecursiveTopologyTree (const TopoDS_Shape & sh, stringstream & str, @@ -332,17 +332,17 @@ namespace netgen bool free, const char * lname); - DLL_HEADER void GetTopologyTree (stringstream & str); + void GetTopologyTree (stringstream & str); - DLL_HEADER void PrintNrShapes (); + void PrintNrShapes (); - DLL_HEADER void CheckIrregularEntities (stringstream & str); + void CheckIrregularEntities (stringstream & str); - DLL_HEADER void SewFaces(); + void SewFaces(); - DLL_HEADER void MakeSolid(); + void MakeSolid(); - DLL_HEADER void HealGeometry(); + void HealGeometry(); // Philippose - 15/01/2009 // Sets the maximum mesh size for a given face @@ -435,13 +435,12 @@ namespace netgen vvispar[i-1].Lowlight(); } - DLL_HEADER void GetUnmeshedFaceInfo (stringstream & str); - DLL_HEADER void GetNotDrawableFaces (stringstream & str); - DLL_HEADER bool ErrorInSurfaceMeshing (); + void GetUnmeshedFaceInfo (stringstream & str); + void GetNotDrawableFaces (stringstream & str); + bool ErrorInSurfaceMeshing (); // void WriteOCC_STL(char * filename); - // DLL_HEADER virtual int GenerateMesh (shared_ptr & mesh, MeshingParameters & mparam); private: bool FastProject (int surfi, Point<3> & ap, double& u, double& v) const; }; From 267e8b33fb29a590a398ae063abe50331cee0473 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Mon, 18 May 2020 15:55:40 +0200 Subject: [PATCH 035/384] cmake - use git to generate version string --- CMakeLists.txt | 14 ++++++++------ cmake/NetgenConfig.cmake.in | 4 ++++ libsrc/core/CMakeLists.txt | 2 ++ libsrc/general/template.hpp | 2 ++ libsrc/meshing/global.cpp | 3 +++ ng/ngappinit.cpp | 2 +- 6 files changed, 20 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 60d82727..a40c89c5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -78,12 +78,8 @@ else() endif() endif() -set(NETGEN_VERSION_MAJOR 6) -set(NETGEN_VERSION_MINOR 2) -string(TIMESTAMP NETGEN_VERSION_PATCH "%y%U%w" ) -set(NETGEN_VERSION "${NETGEN_VERSION_MAJOR}.${NETGEN_VERSION_MINOR}-dev") -set(PACKAGE_VERSION "${NETGEN_VERSION_MAJOR}.${NETGEN_VERSION_MINOR}-${NETGEN_VERSION_PATCH}") -set(CPACK_PACKAGE_VERSION "${PACKAGE_VERSION}") +include (${CMAKE_CURRENT_LIST_DIR}/cmake/generate_version_file.cmake) +set(CPACK_PACKAGE_VERSION "${NETGEN_VERSION}") ####################################################################### @@ -326,6 +322,12 @@ if (USE_MPEG) include_directories(${FFMPEG_INCLUDE_DIR}) endif (USE_MPEG) +####################################################################### +add_custom_target(ng_generate_version_file + ${CMAKE_COMMAND} + -DBDIR=${CMAKE_CURRENT_BINARY_DIR} + -P ${CMAKE_CURRENT_LIST_DIR}/cmake/generate_version_file.cmake + ) ####################################################################### if(INSTALL_PROFILES) file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/netgen.sh "#!/bin/sh\n") diff --git a/cmake/NetgenConfig.cmake.in b/cmake/NetgenConfig.cmake.in index 54f88ac3..58b54055 100644 --- a/cmake/NetgenConfig.cmake.in +++ b/cmake/NetgenConfig.cmake.in @@ -1,4 +1,8 @@ set(NETGEN_VERSION "@NETGEN_VERSION@") +set(NETGEN_VERSION_MAJOR "@NETGEN_VERSION_MAJOR@") +set(NETGEN_VERSION_MINOR "@NETGEN_VERSION_MINOR@") +set(NETGEN_VERSION_PATCH "@NETGEN_VERSION_PATCH@") +set(NETGEN_VERSION_TWEAK "@NETGEN_VERSION_TWEAK@") get_filename_component(NETGEN_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) diff --git a/libsrc/core/CMakeLists.txt b/libsrc/core/CMakeLists.txt index 8a36ba13..f0f07399 100644 --- a/libsrc/core/CMakeLists.txt +++ b/libsrc/core/CMakeLists.txt @@ -71,6 +71,8 @@ if(ENABLE_CPP_CORE_GUIDELINES_CHECK) set_target_properties(ngcore PROPERTIES CXX_CLANG_TIDY "${DO_CLANG_TIDY}") endif(ENABLE_CPP_CORE_GUIDELINES_CHECK) +add_dependencies(ngcore ng_generate_version_file) + if(USE_PYTHON) pybind11_add_module(pyngcore SHARED python_ngcore_export.cpp) target_link_libraries(pyngcore PUBLIC ngcore netgen_python) diff --git a/libsrc/general/template.hpp b/libsrc/general/template.hpp index afca79c7..31fac8d7 100644 --- a/libsrc/general/template.hpp +++ b/libsrc/general/template.hpp @@ -14,6 +14,8 @@ namespace netgen templates, global types, defines and variables */ +DLL_HEADER extern const string netgen_version; + /// The following value may be adapted to the hardware ! #ifndef CLOCKS_PER_SEC #define CLOCKS_PER_SEC 1000000 diff --git a/libsrc/meshing/global.cpp b/libsrc/meshing/global.cpp index bd74162c..9bbce766 100644 --- a/libsrc/meshing/global.cpp +++ b/libsrc/meshing/global.cpp @@ -1,5 +1,6 @@ #include #include "meshing.hpp" +#include namespace netgen @@ -21,6 +22,8 @@ namespace netgen // NetgenOutStream * testout = new NetgenOutStream; + const string netgen_version = NETGEN_VERSION; + ostream * mycout = &cout; ostream * myerr = &cerr; diff --git a/ng/ngappinit.cpp b/ng/ngappinit.cpp index 9e0825a3..bc82e9dd 100644 --- a/ng/ngappinit.cpp +++ b/ng/ngappinit.cpp @@ -82,7 +82,7 @@ int main(int argc, char ** argv) if ( netgen::id == 0 ) { - cout << "NETGEN-" << PACKAGE_VERSION << endl; + cout << "NETGEN-" << netgen::netgen_version << endl; cout << "Developed by Joachim Schoeberl at" << endl << "2010-xxxx Vienna University of Technology" << endl From 34a6777f496f938e5aa00e856211713f03d32949 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Mon, 18 May 2020 17:54:09 +0200 Subject: [PATCH 036/384] add file generate_version_file.cmake --- cmake/generate_version_file.cmake | 49 +++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 cmake/generate_version_file.cmake diff --git a/cmake/generate_version_file.cmake b/cmake/generate_version_file.cmake new file mode 100644 index 00000000..3b913636 --- /dev/null +++ b/cmake/generate_version_file.cmake @@ -0,0 +1,49 @@ +if(NOT BDIR) + set(BDIR ${CMAKE_CURRENT_BINARY_DIR}) +endif() + +find_package(Git REQUIRED) + +if(GIT_FOUND AND EXISTS ${CMAKE_CURRENT_LIST_DIR}/../.git) + execute_process(COMMAND git describe --tags --match "v[0-9]*" --long --dirty WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} OUTPUT_VARIABLE git_version_string) +else() + # for source package files (generated for ubuntu builds on launchpad) read the version from version.txt + if(EXISTS ${CMAKE_CURRENT_LIST_DIR}/../version.txt) + file(READ ${CMAKE_CURRENT_LIST_DIR}/../version.txt git_version_string ) + else() + get_filename_component(git_version_string ${CMAKE_CURRENT_LIST_DIR}/.. NAME) + string(REGEX REPLACE "^netgen(.*)" "\\1" git_version_string "${git_version_string}") + endif() +endif() + +string(REGEX REPLACE "^v([0-9]+)\\..*" "\\1" NETGEN_VERSION_MAJOR "${git_version_string}") +string(REGEX REPLACE "^v[0-9]+\\.([0-9]+).*" "\\1" NETGEN_VERSION_MINOR "${git_version_string}") +string(REGEX REPLACE "^v[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" NETGEN_VERSION_PATCH "${git_version_string}") +string(REGEX REPLACE "^v[0-9]+\\.[0-9]+\\.[0-9]+\\-([0-9]+).*" "\\1" NETGEN_VERSION_TWEAK "${git_version_string}") +string(REGEX REPLACE "^v[0-9]+\\.[0-9]+\\.[0-9]+\\-[0-9]+\\-([0-9a-z]+).*" "\\1" NETGEN_VERSION_HASH "${git_version_string}") + +set(NETGEN_VERSION_SHORT ${NETGEN_VERSION_MAJOR}.${NETGEN_VERSION_MINOR}.${NETGEN_VERSION_PATCH}) +set(NETGEN_VERSION_LONG ${NETGEN_VERSION_SHORT}-${NETGEN_VERSION_TWEAK}-${NETGEN_VERSION_HASH}) + +if(NETGEN_VERSION_TWEAK) + # no release version - nightly build + set(NETGEN_VERSION ${NETGEN_VERSION_LONG}) +else() + # TWEAK is 0 -> current version has a tag assigned + set(NETGEN_VERSION ${NETGEN_VERSION_SHORT}) +endif() + +set(NETGEN_VERSION_LONG ${NETGEN_VERSION_SHORT}-${NETGEN_VERSION_TWEAK}-${NETGEN_VERSION_HASH}) + +set(version_file ${BDIR}/netgen_version.hpp) +set(new_version_file_string "#define NETGEN_VERSION \"${NETGEN_VERSION}\"\n") +if(EXISTS ${version_file}) + file(READ ${version_file} old_version_file_string ) + if(${old_version_file_string} STREQUAL ${new_version_file_string}) + else() + file(WRITE ${BDIR}/netgen_version.hpp ${new_version_file_string}) + endif() +else() + file(WRITE ${BDIR}/netgen_version.hpp ${new_version_file_string}) +endif() + From 897cf6f848584d805538b3813b39894b2af32f03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20Sch=C3=B6berl?= Date: Fri, 22 May 2020 08:15:40 +0200 Subject: [PATCH 037/384] output of xbool --- libsrc/core/xbool.hpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/libsrc/core/xbool.hpp b/libsrc/core/xbool.hpp index 31ca8730..8feb3fef 100644 --- a/libsrc/core/xbool.hpp +++ b/libsrc/core/xbool.hpp @@ -30,7 +30,15 @@ namespace ngcore bool IsTrue () const { return state == 2; } bool IsMaybe () const { return state == 1; } bool IsFalse () const { return state == 0; } + friend ostream & operator<< (ostream & ost, xbool xb); }; + + + static char output[] = "0?1"; + inline ostream & operator<< (ostream & ost, xbool xb) + { + return ost << output[xb.state]; + } } // namespace ngcore From 34590f1b9a54145e256397eb3a8b1ada76dba090 Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Tue, 26 May 2020 11:23:33 +0200 Subject: [PATCH 038/384] support already meshed edges/faces in occ mesher --- libsrc/occ/occgenmesh.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libsrc/occ/occgenmesh.cpp b/libsrc/occ/occgenmesh.cpp index 38902710..314d405a 100644 --- a/libsrc/occ/occgenmesh.cpp +++ b/libsrc/occ/occgenmesh.cpp @@ -365,6 +365,7 @@ namespace netgen { TopoDS_Face face = TopoDS::Face(exp1.Current()); int facenr = geom.fmap.FindIndex(face); + if(facenr < 1) continue; if (face2solid[0][facenr-1] == 0) face2solid[0][facenr-1] = solidnr; @@ -382,8 +383,7 @@ namespace netgen int facenr = 0; - int edgenr = 0; - + int edgenr = mesh.GetNSeg(); (*testout) << "faces = " << geom.fmap.Extent() << endl; int curr = 0; @@ -449,6 +449,8 @@ namespace netgen continue; } + if(geom.emap.FindIndex(edge) < 1) continue; + if (geom.vmap.FindIndex(TopExp::FirstVertex (edge)) == geom.vmap.FindIndex(TopExp::LastVertex (edge))) { From ad525cbfb9b9e3ba2273b145e1945df6708b6f46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20Sch=C3=B6berl?= Date: Tue, 26 May 2020 20:57:25 +0200 Subject: [PATCH 039/384] fix warning --- libsrc/visualization/soldata.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libsrc/visualization/soldata.hpp b/libsrc/visualization/soldata.hpp index 74143fc0..c522f1a3 100644 --- a/libsrc/visualization/soldata.hpp +++ b/libsrc/visualization/soldata.hpp @@ -141,6 +141,7 @@ namespace netgen class DLL_HEADER UserVisualizationObject { public: + virtual ~UserVisualizationObject() { ; } virtual void Draw () = 0; }; From dc15e50956ab802ee98f87438d2bca99a636d764 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20Sch=C3=B6berl?= Date: Sun, 31 May 2020 21:58:21 +0200 Subject: [PATCH 040/384] Added glueing to OCC interface, geom.Glue() from Python --- libsrc/occ/occgeom.cpp | 81 +++++++++++++++++++++++++++++++++++++++ libsrc/occ/occgeom.hpp | 3 +- libsrc/occ/python_occ.cpp | 1 + 3 files changed, 84 insertions(+), 1 deletion(-) diff --git a/libsrc/occ/occgeom.cpp b/libsrc/occ/occgeom.cpp index 037022f9..5328bd03 100644 --- a/libsrc/occ/occgeom.cpp +++ b/libsrc/occ/occgeom.cpp @@ -169,8 +169,89 @@ namespace netgen } + void OCCGeometry :: GlueGeometry() + { + PrintMessage(1, "OCC Glue Geometry"); + /* + // + BRep_Builder builder; + TopoDS_Shape my_fuse; + int cnt = 0; + for (TopExp_Explorer exp_solid(shape, TopAbs_SOLID); exp_solid.More(); exp_solid.Next()) + { + cout << "cnt = " << cnt << endl; + if (cnt == 0) + my_fuse = exp_solid.Current(); + else + // my_fuse = BRepAlgoAPI_Fuse (my_fuse, exp_solid.Current()); + my_fuse = QANewModTopOpe_Glue::QANewModTopOpe_Glue(my_fuse, exp_solid.Current()); + cnt++; + } + cout << "remove" << endl; + // for (int i = 1; i <= somap.Size(); i++) + // builder.Remove (shape, somap(i)); + cout << "now add" << endl; + // builder.Add (shape, my_fuse); + shape = my_fuse; + cout << "build fmap" << endl; + BuildFMap(); + */ + // from + // https://www.opencascade.com/doc/occt-7.4.0/overview/html/occt_user_guides__boolean_operations.html + BOPAlgo_Builder aBuilder; + + // Setting arguments + TopTools_ListOfShape aLSObjects; + for (TopExp_Explorer exp_solid(shape, TopAbs_SOLID); exp_solid.More(); exp_solid.Next()) + aLSObjects.Append (exp_solid.Current()); + aBuilder.SetArguments(aLSObjects); + + // Setting options for GF + // Set parallel processing mode (default is false) + // Standard_Boolean bRunParallel = Standard_True; + // aBuilder.SetRunParallel(bRunParallel); + + // Set Fuzzy value (default is Precision::Confusion()) + // Standard_Real aFuzzyValue = 1.e-5; + // aBuilder.SetFuzzyValue(aFuzzyValue); + + // Set safe processing mode (default is false) + // Standard_Boolean bSafeMode = Standard_True; + // aBuilder.SetNonDestructive(bSafeMode); + + // Set Gluing mode for coinciding arguments (default is off) + // BOPAlgo_GlueEnum aGlue = BOPAlgo_GlueShift; + // aBuilder.SetGlue(aGlue); + + // Disabling/Enabling the check for inverted solids (default is true) + // Standard Boolean bCheckInverted = Standard_False; + // aBuilder.SetCheckInverted(bCheckInverted); + + // Set OBB usage (default is false) + // Standard_Boolean bUseOBB = Standard_True; + // aBuilder.SetUseOBB(buseobb); + + // Perform the operation + aBuilder.Perform(); + // Check for the errors + if (aBuilder.HasErrors()) + { + cout << "builder has errors" << endl; + return; + } + // Check for the warnings + if (aBuilder.HasWarnings()) + { + // treatment of the warnings + ; + } + // result of the operation + shape = aBuilder.Shape(); + BuildFMap(); + } + void OCCGeometry :: HealGeometry () { int nrc = 0, nrcs = 0, diff --git a/libsrc/occ/occgeom.hpp b/libsrc/occ/occgeom.hpp index 372979ad..447d212f 100644 --- a/libsrc/occ/occgeom.hpp +++ b/libsrc/occ/occgeom.hpp @@ -78,7 +78,7 @@ #include "Bnd_Box.hxx" #include "ShapeAnalysis.hxx" #include "ShapeBuild_ReShape.hxx" - +#include "BOPAlgo_Builder.hxx" // Philippose - 29/01/2009 // OpenCascade XDE Support @@ -343,6 +343,7 @@ namespace netgen void MakeSolid(); void HealGeometry(); + void GlueGeometry(); // Philippose - 15/01/2009 // Sets the maximum mesh size for a given face diff --git a/libsrc/occ/python_occ.cpp b/libsrc/occ/python_occ.cpp index 837ecdb0..a7508c31 100644 --- a/libsrc/occ/python_occ.cpp +++ b/libsrc/occ/python_occ.cpp @@ -66,6 +66,7 @@ DLL_HEADER void ExportNgOCC(py::module &m) }), py::arg("filename"), "Load OCC geometry from step, brep or iges file") .def(NGSPickle()) + .def("Glue", &OCCGeometry::GlueGeometry) .def("Heal",[](OCCGeometry & self, double tolerance, bool fixsmalledges, bool fixspotstripfaces, bool sewfaces, bool makesolids, bool splitpartitions) { self.tolerance = tolerance; From 1d97367e30546dbdc5f5504b0be4c917681f1108 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20Sch=C3=B6berl?= Date: Tue, 2 Jun 2020 08:51:51 +0200 Subject: [PATCH 041/384] check OCC-Version of HasErrors --- libsrc/occ/occgeom.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libsrc/occ/occgeom.cpp b/libsrc/occ/occgeom.cpp index 5328bd03..abee8107 100644 --- a/libsrc/occ/occgeom.cpp +++ b/libsrc/occ/occgeom.cpp @@ -236,6 +236,7 @@ namespace netgen // Perform the operation aBuilder.Perform(); // Check for the errors +#if OCC_VERSION_HEX >= 0x070000 if (aBuilder.HasErrors()) { cout << "builder has errors" << endl; @@ -247,6 +248,7 @@ namespace netgen // treatment of the warnings ; } +#endif // result of the operation shape = aBuilder.Shape(); BuildFMap(); From 9b28a2df026753a2ba6dfcdcad3a641799c211a8 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Wed, 3 Jun 2020 11:50:33 +0200 Subject: [PATCH 042/384] OCC - HasErrors() available from v7.2 --- libsrc/occ/occgeom.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsrc/occ/occgeom.cpp b/libsrc/occ/occgeom.cpp index abee8107..91dfb2cf 100644 --- a/libsrc/occ/occgeom.cpp +++ b/libsrc/occ/occgeom.cpp @@ -236,7 +236,7 @@ namespace netgen // Perform the operation aBuilder.Perform(); // Check for the errors -#if OCC_VERSION_HEX >= 0x070000 +#if OCC_VERSION_HEX >= 0x070200 if (aBuilder.HasErrors()) { cout << "builder has errors" << endl; From 94d489e183f569f3ca97c89ebe525be31c7c076f Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Wed, 3 Jun 2020 11:54:56 +0200 Subject: [PATCH 043/384] cmake - remove compiler definition of NETGEN_VERSION --- CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a40c89c5..f67a83b2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -191,7 +191,6 @@ check_include_files (dlfcn.h HAVE_DLFCN_H) if(HAVE_DLFCN_H) add_definitions(-DHAVE_DLFCN_H) endif() -add_definitions(-DNETGEN_VERSION="${NETGEN_VERSION}") include_directories(BEFORE ${CMAKE_CURRENT_BINARY_DIR}) From efbd71c8d58e7715d947eae3636ab48c545c971f Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Wed, 3 Jun 2020 12:42:35 +0200 Subject: [PATCH 044/384] define cmake export compile commands after project --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f67a83b2..db13de81 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,8 +35,6 @@ option( USE_SUPERBUILD "use ccache" ON) set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH}" "${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake_modules") -set(CMAKE_EXPORT_COMPILE_COMMANDS ON) - if(APPLE) set(INSTALL_DIR_DEFAULT /Applications/Netgen.app) else(APPLE) @@ -78,6 +76,8 @@ else() endif() endif() +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + include (${CMAKE_CURRENT_LIST_DIR}/cmake/generate_version_file.cmake) set(CPACK_PACKAGE_VERSION "${NETGEN_VERSION}") From 5bea3bb6122a8526dec8e89bbb6799c8b2ce80ea Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Mon, 8 Jun 2020 10:39:31 +0200 Subject: [PATCH 045/384] Implement and export SplineGeometry2d::SetDomainTensorMeshing --- libsrc/geom2d/geometry2d.hpp | 15 +++++++++++++-- libsrc/geom2d/python_geom2d.cpp | 1 + 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/libsrc/geom2d/geometry2d.hpp b/libsrc/geom2d/geometry2d.hpp index ff4c459c..f5841b19 100644 --- a/libsrc/geom2d/geometry2d.hpp +++ b/libsrc/geom2d/geometry2d.hpp @@ -133,7 +133,7 @@ namespace netgen NgArray materials; NgArray maxh; NgArray quadmeshing; - NgArray tensormeshing; + Array tensormeshing; NgArray layer; NgArray bcnames; double elto0 = 1.0; @@ -216,9 +216,20 @@ namespace netgen } bool GetDomainTensorMeshing ( int domnr ) { - if ( tensormeshing.Size() ) return tensormeshing[domnr-1]; + if ( tensormeshing.Size()>=domnr ) return tensormeshing[domnr-1]; else return false; } + void SetDomainTensorMeshing ( int domnr, bool tm ) + { + if ( tensormeshing.Size()(), meshingparameter_description.c_str()) + .def("_SetDomainTensorMeshing", &SplineGeometry2d::SetDomainTensorMeshing) ; } From d1c7a16d63ba82071957aa21cae74d999c8bb6c5 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Mon, 8 Jun 2020 10:41:22 +0200 Subject: [PATCH 046/384] Do linear interpolation of corresponding edge points in SplineGeometry tensor mesh generation better results for curved domains --- libsrc/geom2d/genmesh2d.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/libsrc/geom2d/genmesh2d.cpp b/libsrc/geom2d/genmesh2d.cpp index 09ef0260..89eaa098 100644 --- a/libsrc/geom2d/genmesh2d.cpp +++ b/libsrc/geom2d/genmesh2d.cpp @@ -527,11 +527,16 @@ namespace netgen for (PointIndex pix = nextpi[c1], ix = 0; pix != c2; pix = nextpi[pix], ix++) + { + Point<3> px = (*mesh)[pix]; for (PointIndex piy = nextpi[c2], iy = 0; piy != c3; piy = nextpi[piy], iy++) { - Point<3> p = (*mesh)[pix] + ( (*mesh)[piy] - (*mesh)[c2] ); - pts[(nex+1)*(iy+1) + ix+1] = mesh -> AddPoint (p , 1, FIXEDPOINT); + double lam = Dist((*mesh)[piy],(*mesh)[c2]) / Dist((*mesh)[c3],(*mesh)[c2]); + auto pix1 = pts[(nex+1)*ney+ix+1]; + auto pnew = px + lam*((*mesh)[pix1]-px); + pts[(nex+1)*(iy+1) + ix+1] = mesh -> AddPoint (pnew, 1, FIXEDPOINT); } + } for (int i = 0; i < ney; i++) for (int j = 0; j < nex; j++) From d08e2daa060da23965f68bfc4b083ae8dd271539 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Mon, 8 Jun 2020 10:42:26 +0200 Subject: [PATCH 047/384] Do edge swapping for faces individually with tensor product meshes If the mesh contains quads, the edge swapping algorithm switches to generic improve, which introduces quads everywhere. This is not intended if one domain contains a tensor product mesh. Thus, call the optimizer for each face if mesh contains quads but mp.quad is not set. --- libsrc/meshing/meshfunc2d.cpp | 45 ++++++++++++++++++++++++++++++++--- 1 file changed, 42 insertions(+), 3 deletions(-) diff --git a/libsrc/meshing/meshfunc2d.cpp b/libsrc/meshing/meshfunc2d.cpp index 88955a36..84f5d399 100644 --- a/libsrc/meshing/meshfunc2d.cpp +++ b/libsrc/meshing/meshfunc2d.cpp @@ -20,6 +20,19 @@ namespace netgen } mesh.Compress(); + bool optimize_swap_separate_faces = false; + if(!mp.quad) + { + bool mixed = false; + ParallelFor( Range(mesh.GetNSE()), [&] (auto i) NETGEN_LAMBDA_INLINE + { + if (mesh[SurfaceElementIndex(i)].GetNP() != 3) + mixed = true; + }); + if(mixed) + optimize_swap_separate_faces = true; + } + const char * optstr = mp.optimize2d.c_str(); int optsteps = mp.optsteps2d; @@ -31,16 +44,42 @@ namespace netgen { case 's': { // topological swap - MeshOptimize2d meshopt(mesh); + MeshOptimize2d meshopt(mesh); meshopt.SetMetricWeight (mp.elsizeweight); - meshopt.EdgeSwapping (0); + + if(optimize_swap_separate_faces) + { + for(auto i : Range(1, mesh.GetNFD()+1)) + { + meshopt.SetFaceIndex(i); + meshopt.EdgeSwapping (0); + } + } + else + { + meshopt.SetFaceIndex(0); + meshopt.EdgeSwapping (0); + } break; } case 'S': { // metric swap MeshOptimize2d meshopt(mesh); meshopt.SetMetricWeight (mp.elsizeweight); - meshopt.EdgeSwapping (1); + + if(optimize_swap_separate_faces) + { + for(auto i : Range(1, mesh.GetNFD()+1)) + { + meshopt.SetFaceIndex(i); + meshopt.EdgeSwapping (1); + } + } + else + { + meshopt.SetFaceIndex(0); + meshopt.EdgeSwapping (1); + } break; } case 'm': From c0f50820cb72d6df5d6411490884dee3a800c834 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Mon, 8 Jun 2020 10:54:02 +0200 Subject: [PATCH 048/384] Add test for SetDomainTensorMeshing --- .../test_splinegeo_tensordomainmeshing.py | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 tests/pytest/test_splinegeo_tensordomainmeshing.py diff --git a/tests/pytest/test_splinegeo_tensordomainmeshing.py b/tests/pytest/test_splinegeo_tensordomainmeshing.py new file mode 100644 index 00000000..0c00ae7d --- /dev/null +++ b/tests/pytest/test_splinegeo_tensordomainmeshing.py @@ -0,0 +1,22 @@ +from netgen.geom2d import * + +def test_tensordomainmeshing(): + geo = SplineGeometry() + w = 10 + h = 0.01 + + p = [ (0, 0), (w, 0), (w, h), (0, h) ] + p = [geo.AppendPoint(*px) for px in p] + + l0 = geo.Append ( ["line", p[0], p[1]], leftdomain=1, rightdomain=0 ) + l1 = geo.Append ( ["line", p[1], p[2]], leftdomain=1, rightdomain=0) + geo.Append ( ["line", p[3], p[2]], leftdomain=0, rightdomain=1, copy=l0 ) + geo.Append ( ["line", p[0], p[3]], leftdomain=0, rightdomain=1, copy=l1 ) + + geo._SetDomainTensorMeshing(1, True) + + mesh = geo.GenerateMesh(maxh=1) + + for el in mesh.Elements2D(): + print(el.vertices) + assert len(el.vertices) == 4 From 09323b2ac46a9b5ad3dab8a84a0706c51ab522bc Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Fri, 12 Jun 2020 14:28:08 +0200 Subject: [PATCH 049/384] Fix AnalyzeEdge() --- libsrc/csg/edgeflw.cpp | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/libsrc/csg/edgeflw.cpp b/libsrc/csg/edgeflw.cpp index 644d2cfa..106a951c 100644 --- a/libsrc/csg/edgeflw.cpp +++ b/libsrc/csg/edgeflw.cpp @@ -1085,23 +1085,33 @@ namespace netgen //int k; double eps = 1e-8*size; - NgArray pre_ok(2); + ArrayMem pre_ok(2); + bool flip = false; do { eps *= 0.5; - pre_ok[0] = (locsol -> VectorIn2 (hp, m, n, eps) == IS_OUTSIDE && - locsol -> VectorIn2 (hp, m, -1. * n, eps) == IS_INSIDE); - pre_ok[1] = (locsol -> VectorIn2 (hp, -1.*m, n, eps) == IS_OUTSIDE && - locsol -> VectorIn2 (hp, -1.*m, -1. * n, eps) == IS_INSIDE); + auto in00 = locsol -> VectorIn2 (hp, m, n, eps); + auto in01 = locsol -> VectorIn2 (hp, m, -1. * n, eps); + pre_ok[0] = in00 == IS_OUTSIDE && in01 == IS_INSIDE; + + if(in00 == IS_INSIDE && in01 == IS_OUTSIDE) + pre_ok[0] = flip = true; + + auto in10 = locsol -> VectorIn2 (hp, -1.*m, n, eps); + auto in11 = locsol -> VectorIn2 (hp, -1.*m, -1. * n, eps); + pre_ok[1] = (in10 == IS_OUTSIDE && in11 == IS_INSIDE); + + if(in10 == IS_INSIDE && in11 == IS_OUTSIDE) + pre_ok[1] = flip = true; if (debug) { *testout << "eps = " << eps << endl; - *testout << "in,1 = " << locsol -> VectorIn2 (hp, m, n, eps) << endl; - *testout << "in,1 = " << locsol -> VectorIn2 (hp, m, -1. * n, eps) << endl; - *testout << "in,1 = " << locsol -> VectorIn2 (hp, -1.*m, n, eps) << endl; - *testout << "in,1 = " << locsol -> VectorIn2 (hp, -1.*m, -1. * n, eps) << endl; + *testout << "in,1 = " << in00 << endl; + *testout << "in,1 = " << in01 << endl; + *testout << "in,1 = " << in10 << endl; + *testout << "in,1 = " << in11 << endl; } } while(pre_ok[0] && pre_ok[1] && eps > 1e-16*size); @@ -1197,7 +1207,10 @@ namespace netgen if (!surf) { - if (sameasref) + bool inside = sameasref; + if(flip) + inside = !inside; + if (inside) refedges.Elem(hi).domin = i; else refedges.Elem(hi).domout = i; From 6a834f13ac16e0b75f9a392650de0dcc90560bff Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Tue, 16 Jun 2020 13:53:36 +0200 Subject: [PATCH 050/384] fix boundary names for boundarylayer --- libsrc/meshing/boundarylayer.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libsrc/meshing/boundarylayer.cpp b/libsrc/meshing/boundarylayer.cpp index ae7c7a30..55960395 100644 --- a/libsrc/meshing/boundarylayer.cpp +++ b/libsrc/meshing/boundarylayer.cpp @@ -163,6 +163,8 @@ namespace netgen domin, domout, -1); fd.SetBCProperty(max_surface_index); mesh.AddFaceDescriptor(fd); + mesh.SetBCName(max_surface_index-1, + "mapped_" + old_fd.GetBCName()); return max_surface_index; } return last_layer_surface_index_map[si]; From ac45a5f736105d1dd0760d5a6c06d4e85ae52f45 Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Tue, 16 Jun 2020 13:54:13 +0200 Subject: [PATCH 051/384] add more information to illegal bc number exception --- libsrc/meshing/meshclass.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsrc/meshing/meshclass.cpp b/libsrc/meshing/meshclass.cpp index b38aeb88..76a22ffc 100644 --- a/libsrc/meshing/meshclass.cpp +++ b/libsrc/meshing/meshclass.cpp @@ -6541,7 +6541,7 @@ namespace netgen return defaultstring; if (bcnr < 0 || bcnr >= bcnames.Size()) - throw NgException ("illegal bc-number"); + throw RangeException("Illegal bc number ", bcnr, 0, bcnames.Size()); if ( bcnames[bcnr] ) return *bcnames[bcnr]; From 3b5c346e639237f303b731b2c9116aa0c034705c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20Sch=C3=B6berl?= Date: Wed, 17 Jun 2020 19:11:17 +0200 Subject: [PATCH 052/384] proper terms --- libsrc/core/array.hpp | 8 ++++---- libsrc/general/ngarray.hpp | 20 ++++++++++---------- libsrc/interface/readtetmesh.cpp | 18 +++++++++--------- libsrc/interface/writeabaqus.cpp | 20 ++++++++++---------- libsrc/interface/writefeap.cpp | 8 ++++---- libsrc/interface/writetet.cpp | 18 +++++++++--------- libsrc/meshing/bcfunctions.cpp | 2 +- libsrc/meshing/bcfunctions.hpp | 2 +- libsrc/meshing/parallelmesh.cpp | 6 +++--- 9 files changed, 51 insertions(+), 51 deletions(-) diff --git a/libsrc/core/array.hpp b/libsrc/core/array.hpp index ccafef6b..a1161001 100644 --- a/libsrc/core/array.hpp +++ b/libsrc/core/array.hpp @@ -1284,7 +1284,7 @@ namespace ngcore /// bubble sort array template - inline void BubbleSort (FlatArray data, FlatArray slave) + inline void BubbleSort (FlatArray data, FlatArray index) { for (size_t i = 0; i < data.Size(); i++) for (size_t j = i+1; j < data.Size(); j++) @@ -1294,9 +1294,9 @@ namespace ngcore data[i] = data[j]; data[j] = hv; - S hvs = slave[i]; - slave[i] = slave[j]; - slave[j] = hvs; + S hvs = index[i]; + index[i] = index[j]; + index[j] = hvs; } } diff --git a/libsrc/general/ngarray.hpp b/libsrc/general/ngarray.hpp index f3eea9d4..fa160a8b 100644 --- a/libsrc/general/ngarray.hpp +++ b/libsrc/general/ngarray.hpp @@ -730,7 +730,7 @@ namespace netgen /// bubble sort array template - inline void BubbleSort (NgFlatArray & data, NgFlatArray & slave) + inline void BubbleSort (NgFlatArray & data, NgFlatArray & index) { for (int i = 0; i < data.Size(); i++) for (int j = i+1; j < data.Size(); j++) @@ -740,16 +740,16 @@ namespace netgen data[i] = data[j]; data[j] = hv; - S hvs = slave[i]; - slave[i] = slave[j]; - slave[j] = hvs; + S hvs = index[i]; + index[i] = index[j]; + index[j] = hvs; } } template void QuickSortRec (NgFlatArray & data, - NgFlatArray & slave, + NgFlatArray & index, int left, int right) { int i = left; @@ -764,20 +764,20 @@ namespace netgen if (i <= j) { ngcore::Swap (data[i], data[j]); - ngcore::Swap (slave[i], slave[j]); + ngcore::Swap (index[i], index[j]); i++; j--; } } while (i <= j); - if (left < j) QuickSortRec (data, slave, left, j); - if (i < right) QuickSortRec (data, slave, i, right); + if (left < j) QuickSortRec (data, index, left, j); + if (i < right) QuickSortRec (data, index, i, right); } template - void QuickSort (NgFlatArray & data, NgFlatArray & slave) + void QuickSort (NgFlatArray & data, NgFlatArray & index) { if (data.Size() > 1) - QuickSortRec (data, slave, 0, data.Size()-1); + QuickSortRec (data, index, 0, data.Size()-1); } diff --git a/libsrc/interface/readtetmesh.cpp b/libsrc/interface/readtetmesh.cpp index e061c722..46607c59 100644 --- a/libsrc/interface/readtetmesh.cpp +++ b/libsrc/interface/readtetmesh.cpp @@ -154,7 +154,7 @@ namespace netgen break; case 7: - // NodeID, X, Y, Z, Type (0=Reg 1=PMaster 2=PSlave 3=CPMaster 4=CPSlave), PID: + // NodeID, X, Y, Z, Type (0=Reg 1=PMaster 2=PMinion 3=CPMaster 4=CPMinion), PID: { cout << "read nodes" << endl; for(int i=0; i> dummyint >> dummyint >> dummyint; break; @@ -254,7 +254,7 @@ namespace netgen break; case 18: - // MasterEdgeID, 3 SlaveEdgeID's, 3 TranslCode (1=dS1 2=dS2 3=dS1+dS2) + // MasterEdgeID, 3 MinionEdgeID's, 3 TranslCode (1=dS1 2=dS2 3=dS1+dS2) for(int i=0; i> dummyint; @@ -266,7 +266,7 @@ namespace netgen break; case 19: - // FaceID, EdgeID0, EdgeID1, EdgeID2, FaceType (0=Reg 1=PMaster 2=PSlave), PID + // FaceID, EdgeID0, EdgeID1, EdgeID2, FaceType (0=Reg 1=PMaster 2=PMinion), PID { //Segment seg; int segnum_ng[3]; @@ -343,7 +343,7 @@ namespace netgen break; case 21: - // MasterFaceID, SlaveFaceID, TranslCode (1=dS1 2=dS2) + // MasterFaceID, MinionFaceID, TranslCode (1=dS1 2=dS2) { Vec<3> randomvec(-1.32834,3.82399,0.5429151); int maxtransl = -1; diff --git a/libsrc/interface/writeabaqus.cpp b/libsrc/interface/writeabaqus.cpp index 916600af..209ac89a 100644 --- a/libsrc/interface/writeabaqus.cpp +++ b/libsrc/interface/writeabaqus.cpp @@ -158,25 +158,25 @@ void WriteAbaqusFormat (const Mesh & mesh, cout << "masternode = " << masternode << " = " << mesh.Point(masternode) << endl; - NgArray slaves(3); + NgArray minions(3); for (i = 1; i <= 3; i++) { mesh.GetIdentifications().GetPairs (i, pairs); for (j = 1; j <= pairs.Size(); j++) { if (pairs.Get(j).I1() == masternode) - slaves.Elem(i) = pairs.Get(j).I2(); + minions.Elem(i) = pairs.Get(j).I2(); } - cout << "slave(" << i << ") = " << slaves.Get(i) - << " = " << mesh.Point(slaves.Get(i)) << endl; + cout << "minion(" << i << ") = " << minions.Get(i) + << " = " << mesh.Point(minions.Get(i)) << endl; } outfile << "**\n" << "*NSET,NSET=CTENODS\n" - << slaves.Get(1) << ", " - << slaves.Get(2) << ", " - << slaves.Get(3) << endl; + << minions.Get(1) << ", " + << minions.Get(2) << ", " + << minions.Get(3) << endl; outfile << "**\n" @@ -190,7 +190,7 @@ void WriteAbaqusFormat (const Mesh & mesh, << "*BOUNDARY, OP=NEW\n"; for (j = 1; j <= 3; j++) { - Vec3d v(mesh.Point(masternode), mesh.Point(slaves.Get(j))); + Vec3d v(mesh.Point(masternode), mesh.Point(minions.Get(j))); double vlen = v.Length(); int dir = 0; if (fabs (v.X()) > 0.9 * vlen) dir = 2; @@ -198,7 +198,7 @@ void WriteAbaqusFormat (const Mesh & mesh, if (fabs (v.Z()) > 0.9 * vlen) dir = 1; if (!dir) cout << "ERROR: Problem with rigid body constraints" << endl; - outfile << slaves.Get(j) << ", " << dir << ",, 0.\n"; + outfile << minions.Get(j) << ", " << dir << ",, 0.\n"; } outfile << "**\n" @@ -223,7 +223,7 @@ void WriteAbaqusFormat (const Mesh & mesh, mpc << "4" << "\n"; mpc << pairs.Get(j).I2() << "," << k << ", -1.0, "; mpc << pairs.Get(j).I1() << "," << k << ", 1.0, "; - mpc << slaves.Get(i) << "," << k << ", 1.0, "; + mpc << minions.Get(i) << "," << k << ", 1.0, "; mpc << masternode << "," << k << ", -1.0 \n"; } } diff --git a/libsrc/interface/writefeap.cpp b/libsrc/interface/writefeap.cpp index dc2574a9..84f71eef 100644 --- a/libsrc/interface/writefeap.cpp +++ b/libsrc/interface/writefeap.cpp @@ -144,11 +144,11 @@ void WriteFEAPFormat (const Mesh & mesh, // BEGIN CONTACT OUTPUT /* - int masterindex, slaveindex; + int masterindex, minionindex; cout << "Master Surface index = "; cin >> masterindex; - cout << "Slave Surface index = "; - cin >> slaveindex; + cout << "Minion Surface index = "; + cin >> minionindex; // CONTACT SURFACE 1 @@ -196,7 +196,7 @@ void WriteFEAPFormat (const Mesh & mesh, Element2d sel = mesh.SurfaceElement(i); if (invertsurf) sel.Invert(); - if (mesh.GetFaceDescriptor(sel.GetIndex ()).BCProperty() == slaveindex) + if (mesh.GetFaceDescriptor(sel.GetIndex ()).BCProperty() == minionindex) { zz++; outfile.width(14); diff --git a/libsrc/interface/writetet.cpp b/libsrc/interface/writetet.cpp index 3bc0ba5a..2dbfa440 100644 --- a/libsrc/interface/writetet.cpp +++ b/libsrc/interface/writetet.cpp @@ -427,7 +427,7 @@ namespace netgen << numedges << " " << numnodes << endl << endl; - outfile << "// NodeID, X, Y, Z, Type (0=Reg 1=PMaster 2=PSlave 3=CPMaster 4=CPSlave), "<< uidpid <<":\n" \ + outfile << "// NodeID, X, Y, Z, Type (0=Reg 1=PMaster 2=PMinion 3=CPMaster 4=CPMinion), "<< uidpid <<":\n" \ << "// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n"; @@ -515,7 +515,7 @@ namespace netgen << "// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" \ << n2 << "\n" \ << "\n" \ - << "// MasterNodeID, SlaveNodeID, TranslCode (1=dS1 2=dS2 3=dS1+dS2):\n" \ + << "// MasterNodeID, MinionNodeID, TranslCode (1=dS1 2=dS2 3=dS1+dS2):\n" \ << "// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n"; for(int i=0; i & volume_weights , NgArray & surface_weights, NgArray & segment_weights) { From d2cb67f681d8ba4635805445e89fbb5909f6ba9a Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Fri, 19 Jun 2020 17:36:48 +0200 Subject: [PATCH 053/384] fix cmake warning --- cmake/cmake_modules/FindOpenCasCade.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/cmake_modules/FindOpenCasCade.cmake b/cmake/cmake_modules/FindOpenCasCade.cmake index e82f8dac..870e8ed5 100644 --- a/cmake/cmake_modules/FindOpenCasCade.cmake +++ b/cmake/cmake_modules/FindOpenCasCade.cmake @@ -27,7 +27,7 @@ endif(WIN32) if(OCC_LIBRARY AND NOT OCC_LIBRARY_DIR) get_filename_component(OCC_LIBRARY_DIR ${OCC_LIBRARY} PATH) -endif(OCC_LIBRARY) +endif(OCC_LIBRARY AND NOT OCC_LIBRARY_DIR) if(OCC_INCLUDE_DIR) file(STRINGS ${OCC_INCLUDE_DIR}/Standard_Version.hxx OCC_MAJOR From c3441344fbf86f7c7cc3a9a7b892230b69f6a54e Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Tue, 23 Jun 2020 18:52:29 +0200 Subject: [PATCH 054/384] set material in tensorproduct mesh in 2d as well --- libsrc/geom2d/genmesh2d.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libsrc/geom2d/genmesh2d.cpp b/libsrc/geom2d/genmesh2d.cpp index 89eaa098..c1eadf1a 100644 --- a/libsrc/geom2d/genmesh2d.cpp +++ b/libsrc/geom2d/genmesh2d.cpp @@ -550,6 +550,10 @@ namespace netgen mesh -> AddSurfaceElement (el); } + char* material; + geometry.GetMaterial(domnr, material); + if(material) + mesh->SetMaterial(domnr, material); } From 177ecc74594456fa66a438099c3ed3a722a3f3b4 Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Wed, 24 Jun 2020 06:41:06 +0000 Subject: [PATCH 055/384] Allow curving of mesh if boundarylayer is flat. If surfnr is larger than nr of surfaces then do linear interpolation for PointInBetween and so on. Some fixes in boundarylayer so that surface numbers are correct. --- libsrc/csg/csgeom.cpp | 1 + libsrc/meshing/boundarylayer.cpp | 132 +++++++++++++------------------ libsrc/meshing/python_mesh.cpp | 18 ++++- 3 files changed, 74 insertions(+), 77 deletions(-) diff --git a/libsrc/csg/csgeom.cpp b/libsrc/csg/csgeom.cpp index 4874f0a9..cc3e4464 100644 --- a/libsrc/csg/csgeom.cpp +++ b/libsrc/csg/csgeom.cpp @@ -130,6 +130,7 @@ namespace netgen Point<3> & newp, EdgePointGeomInfo & newgi) const { Point<3> hnewp = p1+secpoint*(p2-p1); + //(*testout) << "hnewp " << hnewp << " s1 " << surfi1 << " s2 " << surfi2 << endl; if (surfi1 != -1 && surfi2 != -1 && surfi1 != surfi2) { diff --git a/libsrc/meshing/boundarylayer.cpp b/libsrc/meshing/boundarylayer.cpp index 55960395..3ce5891a 100644 --- a/libsrc/meshing/boundarylayer.cpp +++ b/libsrc/meshing/boundarylayer.cpp @@ -159,7 +159,8 @@ namespace netgen auto& old_fd = mesh.GetFaceDescriptor(si); int domout = blp.outside ? old_fd.DomainOut() : blp.new_matnrs[layer-1]; int domin = blp.outside ? blp.new_matnrs[layer-1] : old_fd.DomainIn(); - FaceDescriptor fd(max_surface_index-1, + // -1 surf nr is so that curving does not do anything + FaceDescriptor fd(-1, domin, domout, -1); fd.SetBCProperty(max_surface_index); mesh.AddFaceDescriptor(fd); @@ -271,55 +272,53 @@ namespace netgen if(blp.grow_edges) for(SegmentIndex sei = 0; sei < nseg; sei++) { - PointIndex seg_p1 = mesh[sei][0]; - PointIndex seg_p2 = mesh[sei][1]; + auto& segi = mesh[sei]; // Only go in if the segment is still active, and if both its // surface index is part of the "hit-list" if(segsel.Test(sei)) { - if(blp.surfid.Contains(mesh[sei].si)) - { - // clear the bit to indicate that this segment has been processed - segsel.Clear(sei); - - // Find matching segment pair on other surface - for(SegmentIndex sej = 0; sej < nseg; sej++) + if(blp.surfid.Contains(segi.si)) { - PointIndex segpair_p1 = mesh[sej][1]; - PointIndex segpair_p2 = mesh[sej][0]; + // clear the bit to indicate that this segment has been processed + segsel.Clear(sei); - // Find the segment pair on the neighbouring surface element - // Identified by: seg1[0] = seg_pair[1] and seg1[1] = seg_pair[0] - if(segsel.Test(sej) && ((segpair_p1 == seg_p1) && (segpair_p2 == seg_p2))) + // Find matching segment pair on other surface + for(SegmentIndex sej = 0; sej < nseg; sej++) { - // clear bit to indicate that processing of this segment is done - segsel.Clear(sej); + auto& segj = mesh[sej]; + // Find the segment pair on the neighbouring surface element + // Identified by: seg1[0] = seg_pair[1] and seg1[1] = seg_pair[0] + if(segsel.Test(sej) && ((segi[0] == segj[1]) && (segi[1] == segj[0]))) + { + // clear bit to indicate that processing of this segment is done + segsel.Clear(sej); - // Only worry about those surfaces which are not in the - // boundary layer list - if(!blp.surfid.Contains(mesh[sej].si)) + // if segj is not in surfel list we nned to add quads + if(!blp.surfid.Contains(segj.si)) { SurfaceElementIndex pnt_commelem; SetInvalid(pnt_commelem); - auto pnt1_elems = meshtopo.GetVertexSurfaceElements(segpair_p1); - auto pnt2_elems = meshtopo.GetVertexSurfaceElements(segpair_p2); + auto pnt1_elems = meshtopo.GetVertexSurfaceElements(segj[0]); + auto pnt2_elems = meshtopo.GetVertexSurfaceElements(segj[1]); for(auto pnt1_sei : pnt1_elems) - if(mesh[pnt1_sei].GetIndex() == mesh[sej].si) + if(mesh[pnt1_sei].GetIndex() == segj.si) for(auto pnt2_sei : pnt2_elems) if(pnt1_sei == pnt2_sei) pnt_commelem = pnt1_sei; if(IsInvalid(pnt_commelem)) - throw Exception("Couldn't find element on other side for " + ToString(segpair_p1) + " to " + ToString(segpair_p2)); + throw Exception("Couldn't find element on other side for " + ToString(segj[0]) + " to " + ToString(segj[1])); const auto& commsel = mesh[pnt_commelem]; auto surfelem_vect = GetSurfaceNormal(mesh, commsel); if(blp.outside) surfelem_vect *= -1; Element2d sel(QUAD); + auto seg_p1 = segi[0]; + auto seg_p2 = segi[1]; if(blp.outside) Swap(seg_p1, seg_p2); sel[0] = seg_p1; @@ -332,7 +331,7 @@ namespace netgen { domains_to_surf_index[domains] = ++max_surface_index; domains_to_surf_index[make_tuple(max_surface_index, get<1>(domains), get<2>(domains))] = max_surface_index; - FaceDescriptor fd(max_surface_index-1, + FaceDescriptor fd(-1, get<1>(domains), get<2>(domains), -1); @@ -367,46 +366,37 @@ namespace netgen seg_2.edgenr = pi_to_edgenr[points]; seg_2.si = new_index; mesh.AddSegment(seg_2); - mesh[sej].si = new_index; } // in last layer insert new segments if(layer == blp.heights.Size()) { - Segment s1 = mesh[sei]; - Segment s2 = mesh[sej]; + Segment s1 = segi; + Segment s2 = segj; s1.edgenr = ++max_edge_nr; s2.edgenr = max_edge_nr; - bool create_it = true; - if(blp.surfid.Contains(mesh[sej].si)) - { - if(last_layer_surface_index_map.find(s1.si) != last_layer_surface_index_map.end() && - last_layer_surface_index_map.find(s2.si) != last_layer_surface_index_map.end()) - // edge already mapped - create_it = false; - s2.si = map_surface_index(s2.si); - } + if(blp.surfid.Contains(segj.si)) + s2.si = map_surface_index(segj.si); else { - s2.si = domains_to_surf_index[make_tuple(s2.si, - blp.new_matnrs[layer-1], mesh.GetFaceDescriptor(s2.si).DomainOut())]; + auto side_surf = domains_to_surf_index[make_tuple(s2.si, blp.new_matnrs[layer-1], mesh.GetFaceDescriptor(s2.si).DomainOut())]; + if(blp.outside) + s2.si = side_surf; + else + segj.si = side_surf; } s1.si = map_surface_index(s1.si); - if(create_it) - { - mesh.AddSegment(s1); - mesh.AddSegment(s2); - } + s1.surfnr1 = s1.surfnr2 = s2.surfnr1 = s2.surfnr2 = -1; + mesh.AddSegment(s1); + mesh.AddSegment(s2); + } + // segi[0] = mapto[segi[0]] not working somehow? + mesh[sei][0] = mapto[segi[0]]; + mesh[sei][1] = mapto[segi[1]]; + mesh[sej][0] = mapto[segj[0]]; + mesh[sej][1] = mapto[segj[1]]; } - - // remap the segments to the new points - mesh[sei][0] = mapto[mesh[sei][0]]; - mesh[sei][1] = mapto[mesh[sei][1]]; - mesh[sej][1] = mapto[mesh[sej][1]]; - mesh[sej][0] = mapto[mesh[sej][0]]; - } - } } else { @@ -457,9 +447,9 @@ namespace netgen { for(SurfaceElementIndex si = 0; si < nse; si++) { - if(blp.surfid.Contains(mesh[si].GetIndex())) + const auto& sel = mesh[si]; + if(blp.surfid.Contains(sel.GetIndex())) { - const auto& sel = mesh[si]; Element2d newel = sel; newel.SetIndex(map_surface_index(sel.GetIndex())); mesh.AddSurfaceElement(newel); @@ -548,36 +538,28 @@ namespace netgen for(SurfaceElementIndex sei : Range(nse)) { auto& sel = mesh[sei]; - bool to_move = blp.surfid.Contains(sel.GetIndex()); - if(blp.domains.Size()) + if(!blp.surfid.Contains(sel.GetIndex())) { - if(blp.outside) - to_move |= blp.domains[mesh.GetFaceDescriptor(sel.GetIndex()).DomainIn()]; - else - to_move |= !blp.domains[mesh.GetFaceDescriptor(sel.GetIndex()).DomainIn()]; - } - - if(to_move) - { - for(auto& pnum : sel.PNums()) - // Check (Doublecheck) if the corresponding point has a - // copy available for remapping - if(mapto[pnum].IsValid()) - // Map the surface elements to the new points - pnum = mapto[pnum]; + const auto& fd = mesh.GetFaceDescriptor(sel.GetIndex()); + if(blp.outside && + (!blp.domains[fd.DomainIn()] && !blp.domains[fd.DomainOut()])) + continue; + if(!blp.outside && + (blp.domains[fd.DomainIn()] || blp.domains[fd.DomainOut()])) + continue; } + for(auto& pnum : sel.PNums()) + if(mapto[pnum].IsValid()) + pnum = mapto[pnum]; } for(ElementIndex ei : Range(ne)) { auto& el = mesh[ei]; - bool to_move = blp.outside ? blp.domains[el.GetIndex()] : !blp.domains[el.GetIndex()]; - if(blp.domains.Size() == 0 || to_move) + // only move the elements on the correct side + if(blp.outside ? blp.domains[el.GetIndex()] : !blp.domains[el.GetIndex()]) for(auto& pnum : el.PNums()) - // Check (Doublecheck) if the corresponding point has a - // copy available for remapping if(mapto[pnum].IsValid()) - // Map the volume elements to the new points pnum = mapto[pnum]; } diff --git a/libsrc/meshing/python_mesh.cpp b/libsrc/meshing/python_mesh.cpp index fdfb2c40..60c719e7 100644 --- a/libsrc/meshing/python_mesh.cpp +++ b/libsrc/meshing/python_mesh.cpp @@ -949,8 +949,22 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m) { regex pattern(*get_if(&boundary)); for(int i = 1; i<=self.GetNFD(); i++) - if(regex_match(self.GetFaceDescriptor(i).GetBCName(), pattern)) - blp.surfid.Append(i); + { + auto& fd = self.GetFaceDescriptor(i); + if(regex_match(fd.GetBCName(), pattern)) + { + auto dom_pattern = get_if(&domain); + // only add if adjacent to domain + if(dom_pattern) + { + regex pattern(*dom_pattern); + if(regex_match(self.GetMaterial(fd.DomainIn()), pattern) || (fd.DomainOut() > 0 ? regex_match(self.GetMaterial(fd.DomainOut()), pattern) : false)) + blp.surfid.Append(i); + } + else + blp.surfid.Append(i); + } + } } if(double* pthickness = get_if(&thickness); pthickness) From 1a619841b2b9da67f1b851fd1e004cb0f34f986c Mon Sep 17 00:00:00 2001 From: Michael Neunteufel Date: Wed, 24 Jun 2020 06:41:55 +0000 Subject: [PATCH 056/384] Surface geom --- libsrc/meshing/CMakeLists.txt | 4 +- libsrc/meshing/curvedelems.cpp | 30 +-- libsrc/meshing/meshing.hpp | 2 + libsrc/meshing/python_mesh.cpp | 39 +++ libsrc/meshing/surfacegeom.cpp | 419 +++++++++++++++++++++++++++++++++ libsrc/meshing/surfacegeom.hpp | 70 ++++++ 6 files changed, 547 insertions(+), 17 deletions(-) create mode 100644 libsrc/meshing/surfacegeom.cpp create mode 100644 libsrc/meshing/surfacegeom.hpp diff --git a/libsrc/meshing/CMakeLists.txt b/libsrc/meshing/CMakeLists.txt index 47b99e79..9bf45a89 100644 --- a/libsrc/meshing/CMakeLists.txt +++ b/libsrc/meshing/CMakeLists.txt @@ -12,7 +12,7 @@ add_library(mesh ${NG_LIB_TYPE} smoothing2.cpp smoothing3.cpp specials.cpp tetrarls.cpp topology.cpp triarls.cpp validate.cpp bcfunctions.cpp parallelmesh.cpp paralleltop.cpp paralleltop.hpp basegeom.cpp - python_mesh.cpp hexarls.cpp + python_mesh.cpp hexarls.cpp surfacegeom.cpp ../../ng/onetcl.cpp ${mesh_object_libs} ) @@ -37,6 +37,6 @@ install(FILES localh.hpp meshclass.hpp meshfunc.hpp meshing2.hpp meshing3.hpp meshing.hpp meshtool.hpp meshtype.hpp msghandler.hpp paralleltop.hpp ruler2.hpp ruler3.hpp specials.hpp topology.hpp validate.hpp - python_mesh.hpp + python_mesh.hpp surfacegeom.hpp DESTINATION ${NG_INSTALL_DIR_INCLUDE}/meshing COMPONENT netgen_devel ) diff --git a/libsrc/meshing/curvedelems.cpp b/libsrc/meshing/curvedelems.cpp index 6523c056..7ea1086b 100644 --- a/libsrc/meshing/curvedelems.cpp +++ b/libsrc/meshing/curvedelems.cpp @@ -748,21 +748,19 @@ namespace netgen for (int i2 = 0; i2 < edgenrs.Size(); i2++) { - // PointIndex pi1 = el[edges[i2][0]]; - // PointIndex pi2 = el[edges[i2][1]]; - - // bool swap = pi1 > pi2; - - // Point<3> p1 = mesh[pi1]; - // Point<3> p2 = mesh[pi2]; - - // int order1 = edgeorder[edgenrs[i2]]; - // int ndof = max (0, order1-1); - - surfnr[edgenrs[i2]] = mesh.GetFaceDescriptor(el.GetIndex()).SurfNr(); - gi0[edgenrs[i2]] = el.GeomInfoPi(edges[i2][0]+1); - gi1[edgenrs[i2]] = el.GeomInfoPi(edges[i2][1]+1); - } + auto enr = edgenrs[i2]; + surfnr[enr] = mesh.GetFaceDescriptor(el.GetIndex()).SurfNr(); + if (el[edges[i2][0]] < el[edges[i2][1]]) + { + gi0[enr] = el.GeomInfoPi(edges[i2][0]+1); + gi1[enr] = el.GeomInfoPi(edges[i2][1]+1); + } + else + { + gi1[enr] = el.GeomInfoPi(edges[i2][0]+1); + gi0[enr] = el.GeomInfoPi(edges[i2][1]+1); + } + } } @@ -1303,6 +1301,8 @@ namespace netgen SurfaceElementIndex sei = top.GetFace2SurfaceElement (f+1)-1; if (sei != SurfaceElementIndex(-1)) { PointGeomInfo gi = mesh[sei].GeomInfoPi(1); + gi.u = 1.0/3.0*(mesh[sei].GeomInfoPi(1).u+mesh[sei].GeomInfoPi(2).u+mesh[sei].GeomInfoPi(3).u); + gi.v = 1.0/3.0*(mesh[sei].GeomInfoPi(1).v+mesh[sei].GeomInfoPi(2).v+mesh[sei].GeomInfoPi(3).v); geo.ProjectPointGI(surfnr[facenr], pp, gi); } else diff --git a/libsrc/meshing/meshing.hpp b/libsrc/meshing/meshing.hpp index 35cb9add..253f2f93 100644 --- a/libsrc/meshing/meshing.hpp +++ b/libsrc/meshing/meshing.hpp @@ -57,10 +57,12 @@ namespace netgen #include "hprefinement.hpp" #include "boundarylayer.hpp" #include "specials.hpp" + } #include "validate.hpp" #include "basegeom.hpp" +#include "surfacegeom.hpp" #ifdef PARALLEL #include "paralleltop.hpp" diff --git a/libsrc/meshing/python_mesh.cpp b/libsrc/meshing/python_mesh.cpp index fdfb2c40..6584878e 100644 --- a/libsrc/meshing/python_mesh.cpp +++ b/libsrc/meshing/python_mesh.cpp @@ -1132,6 +1132,45 @@ grow_edges : bool = False m.def("ReadCGNSFile", &ReadCGNSFile, py::arg("filename"), py::arg("base")=1, "Read mesh and solution vectors from CGNS file"); + + py::class_> (m, "SurfaceGeometry") + .def(py::init<>()) + .def(py::init([](py::object pyfunc) + { + std::function (Point<2>)> func = [pyfunc](Point<2> p) + { + py::gil_scoped_acquire aq; + py::tuple pyres = py::extract(pyfunc(p[0],p[1],0.0)) (); + return Vec<3>(py::extract(pyres[0])(),py::extract(pyres[1])(),py::extract(pyres[2])()); + }; + auto geo = make_shared(func); + return geo; + }), py::arg("mapping")) + .def(NGSPickle()) + .def("GenerateMesh", [](shared_ptr geo, + bool quads, int nx, int ny, bool flip_triangles, py::list py_bbbpts, py::list py_bbbnames) + { + if (py::len(py_bbbpts) != py::len(py_bbbnames)) + throw Exception("In SurfaceGeometry::GenerateMesh bbbpts and bbbnames do not have same lengths."); + Array> bbbpts(py::len(py_bbbpts)); + Array bbbname(py::len(py_bbbpts)); + for(int i = 0; i(py_bbbpts[i])(); + bbbpts[i] = Point<3>(py::extract(pnt[0])(),py::extract(pnt[1])(),py::extract(pnt[2])()); + bbbname[i] = py::extract(py_bbbnames[i])(); + } + auto mesh = make_shared(); + SetGlobalMesh (mesh); + mesh->SetGeometry(geo); + ng_geometry = geo; + auto result = geo->GenerateMesh (mesh, quads, nx, ny, flip_triangles, bbbpts, bbbname); + if(result != 0) + throw Exception("SurfaceGeometry: Meshing failed!"); + return mesh; + }, py::arg("quads")=true, py::arg("nx")=10, py::arg("ny")=10, py::arg("flip_triangles")=false, py::arg("bbbpts")=py::list(), py::arg("bbbnames")=py::list()) + ; + ; } PYBIND11_MODULE(libmesh, m) { diff --git a/libsrc/meshing/surfacegeom.cpp b/libsrc/meshing/surfacegeom.cpp new file mode 100644 index 00000000..40d272a8 --- /dev/null +++ b/libsrc/meshing/surfacegeom.cpp @@ -0,0 +1,419 @@ +/* *************************************************************************/ +/* File: surfacegeom.cpp */ +/* Author: Michael Neunteufel */ +/* Date: Jun. 2020 */ +/* *************************************************************************/ + +#include + +namespace netgen +{ + SurfaceGeometry :: SurfaceGeometry() + { + //identity + func = [](Point<2> p) { return Vec<3>(p[0],p[1],0.0); }; + } + + SurfaceGeometry :: SurfaceGeometry(function(Point<2>)> _func) : func(_func) + { + ; + } + + SurfaceGeometry :: SurfaceGeometry(const SurfaceGeometry& geom) : func(geom.func), eps(geom.eps) + { + ; + } + + void SurfaceGeometry :: CalcHesse(double u, double v, Vec<3>& f_uu, Vec<3>& f_vv, Vec<3>& f_uv) const + { + Point<2> p = Point<2>(u,v); + double pr = p[0]+eps; + double pl = p[0]-eps; + double prr = p[0]+2*eps; + double pll = p[0]-2*eps; + + auto dr = GetTangentVectors( pr, v ); + auto dl = GetTangentVectors( pl, v ); + auto drr = GetTangentVectors( prr, v ); + auto dll = GetTangentVectors( pll, v ); + + f_uu = (1.0/(12.0*eps)) * (8.0*dr[0]-8.0*dl[0]-drr[0]+dll[0]); + f_uv = (1.0/(12.0*eps)) * (8.0*dr[1]-8.0*dl[1]-drr[1]+dll[1]); + + pr = p[1]+eps; + pl = p[1]-eps; + prr = p[1]+2*eps; + pll = p[1]-2*eps; + + dr = GetTangentVectors(u, pr); + dl = GetTangentVectors(u, pl); + drr = GetTangentVectors(u, prr); + dll = GetTangentVectors(u, pll); + + f_vv = (1.0/(12.0*eps)) * (8.0*dr[1]-8.0*dl[1]-drr[1]+dll[1]); + } + + Array> SurfaceGeometry :: GetTangentVectors(double u, double v) const + { + Array> tang(2); + + Point<2> pru = Point<2>(u+eps,v); + Point<2> plu = Point<2>(u-eps,v); + Point<2> prru = Point<2>(u+2*eps,v); + Point<2> pllu = Point<2>(u-2*eps,v); + + Point<2> prv = Point<2>(u,v+eps); + Point<2> plv = Point<2>(u,v-eps); + Point<2> prrv = Point<2>(u,v+2*eps); + Point<2> pllv = Point<2>(u,v-2*eps); + + + tang[0] = 1/(12.0*eps)*( 8.0*func(pru) - 8.0*func(plu) - func(prru) + func(pllu) ); + tang[1] = 1/(12.0*eps)*( 8.0*func(prv) - 8.0*func(plv) - func(prrv) + func(pllv) ); + + return tang; + } + + Vec<3> SurfaceGeometry :: GetNormal(int surfind, const Point<3> & p, const PointGeomInfo* gi) const + { + Array> tang = GetTangentVectors(gi->u, gi->v); + auto normal = Cross(tang[0], tang[1]); + return Cross(tang[0], tang[1]); + } + + + PointGeomInfo SurfaceGeometry :: ProjectPoint(int surfind, Point<3> & p) const + { + throw Exception("In SurfaceGeometry::ProjectPoint"); + } + + void SurfaceGeometry :: ProjectPointEdge (int surfind, int surfind2, Point<3> & p, + EdgePointGeomInfo* gi) const + { + if (gi == nullptr) + throw Exception("In SurfaceGeometry::ProjectPointEdge: gi is nullptr"); + throw Exception("In SurfaceGeometry::ProjectPointEdge: not implemented"); + } + + bool SurfaceGeometry :: ProjectPointGI (int surfind, Point<3> & p, PointGeomInfo & gi) const + { + Array> tangs; + Vec<3> diff, f_uu, f_vv, f_uv; + Vec<2> r, dx; + double norm_r, det, energy=0.0, new_energy=0.0, alpha=2.0,u=0.0,v=0.0; + Mat<2,2> mat, inv; + int num=0, maxit=20; + double damping=0.2; + + + //Solve minimization problem + // argmin_(u,v) 0.5*\| f(u,v)-p\|^2 + //via Neton's method: + // F(u,v) = ( (f(u,v)-p)*f_u(u,v), (f(u,v)-p)*f_v(u,v))^T = (0,0)^T + //Stiffness matrix + // F'(u,v) = ( f_u*f_u + (f-p)*f_uu, f_v*f_u + (f-p)*f_uv, f_v*f_u + (f-p)*f_uv, f_v*f_v + (f-p)*f_vv ) + do + { + num++; + tangs = GetTangentVectors(gi.u, gi.v); + diff = func(Point<2>(gi.u, gi.v)) - Vec<3>(p); + energy = diff.Length2(); + r = Vec<2>( diff*tangs[0], diff*tangs[1] ); + norm_r = r.Length2(); + + CalcHesse(gi.u, gi.v, f_uu, f_vv, f_uv); + + + mat(0,0) = tangs[0]*tangs[0] + diff*f_uu; + mat(1,0) = mat(0,1) = tangs[0]*tangs[1]+diff*f_uv; + mat(1,1) = tangs[1]*tangs[1]+diff*f_vv; + + CalcInverse(mat,inv); + + dx = inv*r; + + //Linesearch + alpha = 2.0; + do + { + alpha /= 2.0; + u = gi.u - min(1.0,alpha*damping*num)*dx[0]; + v = gi.v - min(1.0,alpha*damping*num)*dx[1]; + + diff = func(Point<2>(u, v)) - Vec<3>(p); + new_energy = diff.Length2(); + } + while (alpha > 1e-10 && new_energy > energy+1e-14); + if (alpha <= 1e-10) + throw Exception("In SurfaceGeometry::ProjectPointGI: Linesearch min alpha reached!"); + gi.u = u; + gi.v = v; + + + } + while ( norm_r > 1e-12 && num < maxit); + + //Stay in reference domain [0,1]^2 + if (gi.u < 0 || gi.u > 1 || gi.v < 0 || gi.v > 1) + { + cout << "Warning: Projected point outside [0,1]^2: u=" << gi.u << ",v=" << gi.v <<". Setting back." << endl; + gi.u = min(max(gi.u,0.0),1.0); + gi.v = min(max(gi.v,0.0),1.0); + } + + p = Point<3>(func(Point<2>(gi.u,gi.v))); + + if (num == maxit) + { + //cout << "In SurfaceGeometry::ProjectPointGI: Newton did not converge" << endl; + throw Exception("In SurfaceGeometry::ProjectPointGI: Newton did not converge"); + } + return true; + } + + bool SurfaceGeometry :: CalcPointGeomInfo(int surfind, PointGeomInfo& gi, const Point<3> & p3) const + { + throw Exception("In SurfaceGeometry::CalcPointGeomInfo: not implemented"); + return false; + } + + void SurfaceGeometry :: PointBetweenEdge(const Point<3> & p1, const Point<3> & p2, double secpoint, int surfi1, int surfi2, const EdgePointGeomInfo & ap1, const EdgePointGeomInfo & ap2, Point<3> & newp, EdgePointGeomInfo & newgi) const + { + newp = p1+secpoint*(p2-p1); + + PointGeomInfo pgi; + pgi.u = ap1.u+secpoint*(ap2.u-ap1.u); + pgi.v = ap1.v+secpoint*(ap2.v-ap1.v); + + ProjectPointGI(surfi1, newp, pgi); + + newgi.u = pgi.u; + newgi.v = pgi.v; + newgi.edgenr = ap1.edgenr; + newgi.body = -1; + newgi.dist = -1.0; + } + + void SurfaceGeometry :: PointBetween(const Point<3> & p1, const Point<3> & p2, double secpoint, + int surfi, + const PointGeomInfo & gi1, + const PointGeomInfo & gi2, + Point<3> & newp, PointGeomInfo & newgi) const + { + newp = p1+secpoint*(p2-p1); + + newgi.u = gi1.u+secpoint*(gi2.u-gi1.u); + newgi.v = gi1.v+secpoint*(gi2.v-gi1.v); + newgi.trignum = -1; + + ProjectPointGI(surfi, newp, newgi); + } + + int SurfaceGeometry :: GenerateMesh(shared_ptr & mesh, bool quads, int nx, int ny, bool flip_triangles, const Array>& bbbpts, const Array& bbbnames) + { + mesh->SetDimension(3); + + Array found(bbbpts.Size()); + found = false; + Array indbbbpts(bbbpts.Size()); + + + Array pids; + Array pgis; + for(int i=0; i <= ny; i++) + for(int j=0; j <= nx; j++) + { + PointGeomInfo pgi; + pgi.trignum = -1; + pgi.u = double(j)/nx; + pgi.v = double(i)/ny; + + Point<3> pnt = Point<3>(func(Point<2>(pgi.u,pgi.v))); + pids.Append(mesh->AddPoint(pnt)); + pgis.Append(pgi); + + for (int k = 0; k < bbbpts.Size(); k++) + { + auto diff = pnt - bbbpts[k]; + if(diff.Length2() < 1e-14) + { + found[k] = true; + indbbbpts[k] = pids[pids.Size()-1]; + } + } + } + + for (bool f : found) + if (!f) + throw Exception("In SurfaceGeometry :: GenerateMesh: bbbpts not resolved in mesh."); + + FaceDescriptor fd; + fd.SetSurfNr(1); + fd.SetDomainIn(1); + fd.SetDomainOut(0); + fd.SetBCProperty(1); + mesh->AddFaceDescriptor(fd); + + + for(int i=0; i < ny; i++) + { + for(int j=0; j < nx; j++) + { + int base = i * (nx+1) + j; + if (quads) + { + int pnum[4] = {base,base+1,base+nx+2,base+nx+1}; + Element2d el = Element2d(QUAD); + for (int i = 0; i < 4; i++) + { + el[i] = pids[pnum[i]]; + el.GeomInfoPi(i+1) = pgis[pnum[i]]; + } + el.SetIndex(1); + + mesh->AddSurfaceElement(el); + } + else + { + Array pnum1(3); + Array pnum2(3); + if (flip_triangles) + { + pnum1[0] = base; + pnum1[1] = base+1; + pnum1[2] = base+nx+2; + pnum2[0] = base; + pnum2[1] = base+nx+2; + pnum2[2] = base+nx+1; + } + else + { + pnum1[0] = base; + pnum1[1] = base+1; + pnum1[2] = base+nx+1; + pnum2[0] = base+1; + pnum2[1] = base+nx+2; + pnum2[2] = base+nx+1; + } + + Element2d el = Element2d(TRIG); + for (int i = 0; i < 3; i++) + { + el[i] = pids[pnum1[i]]; + el.GeomInfoPi(i+1) = pgis[pnum1[i]]; + } + el.SetIndex(1); + + mesh->AddSurfaceElement(el); + for (int i = 0; i < 3; i++) + { + el[i] = pids[pnum2[i]]; + el.GeomInfoPi(i+1) = pgis[pnum2[i]]; + } + mesh->AddSurfaceElement(el); + } + } + } + + Segment seg; + seg.si = 1; + seg.edgenr = 1; + seg.epgeominfo[0].edgenr = 1; + seg.epgeominfo[1].edgenr = 1; + // needed for codim2 in 3d + seg.edgenr = 1; + for(int i=0; i < nx; i++) + { + seg[0] = pids[i]; + seg[1] = pids[i+1]; + + seg.geominfo[0] = pgis[i]; + seg.geominfo[1] = pgis[i+1]; + seg.epgeominfo[0].u = pgis[i].u; + seg.epgeominfo[0].v = pgis[i].v; + seg.epgeominfo[0].edgenr = seg.edgenr; + seg.epgeominfo[1].u = pgis[i+1].u; + seg.epgeominfo[1].v = pgis[i+1].v; + seg.epgeominfo[1].edgenr = seg.edgenr; + + mesh->AddSegment(seg); + } + + seg.si = 2; + seg.edgenr = 2; + for(int i=0; iAddSegment(seg); + } + + seg.si = 3; + seg.edgenr = 3; + for(int i=0; iAddSegment(seg); + } + + seg.si = 4; + seg.edgenr = 4; + for(int i=0; iAddSegment(seg); + } + + mesh->SetCD2Name(1, "bottom"); + mesh->SetCD2Name(2, "right"); + mesh->SetCD2Name(3, "top"); + mesh->SetCD2Name(4, "left"); + + for (int i = 0; i < bbbpts.Size(); i++) + { + Element0d el; + el.pnum = indbbbpts[i]; + el.index = i+1; + mesh->pointelements.Append(el); + mesh->SetCD3Name(i+1, bbbnames[i]); + } + + mesh->Compress(); + mesh->UpdateTopology(); + + return 0; + } + +}; diff --git a/libsrc/meshing/surfacegeom.hpp b/libsrc/meshing/surfacegeom.hpp new file mode 100644 index 00000000..25ca73c1 --- /dev/null +++ b/libsrc/meshing/surfacegeom.hpp @@ -0,0 +1,70 @@ +#ifndef FILE_SURFACEGEOM +#define FILE_SURFACEGEOM + +/* *************************************************************************/ +/* File: surfacegeom.hpp */ +/* Author: Michael Neunteufel */ +/* Date: Jun. 2020 */ +/* *************************************************************************/ + + +#include + + +namespace netgen +{ + + class DLL_HEADER SurfaceGeometry : public NetgenGeometry + { + function(Point<2>)> func; + double eps=1e-4; + + private: + + void CalcHesse(double u, double v, Vec<3>& f_uu, Vec<3>& f_vv, Vec<3>& f_uv) const; + public: + + SurfaceGeometry(); + SurfaceGeometry(function(Point<2>)> func); + SurfaceGeometry(const SurfaceGeometry& geom); + SurfaceGeometry& operator =(const SurfaceGeometry& geom) + { + func = geom.func; + eps = geom.eps; + return *this; + } + + Array> GetTangentVectors(double u, double v) const; + + virtual Vec<3> GetNormal(int surfind, const Point<3> & p, const PointGeomInfo* gi) const override; + + virtual PointGeomInfo ProjectPoint(int surfind, Point<3> & p) const override; + + virtual void ProjectPointEdge (int surfind, int surfind2, Point<3> & p, + EdgePointGeomInfo* gi = nullptr) const override; + + virtual bool ProjectPointGI (int surfind, Point<3> & p, PointGeomInfo & gi) const override; + + virtual bool CalcPointGeomInfo(int surfind, PointGeomInfo& gi, const Point<3> & p3) const override; + + virtual void PointBetweenEdge(const Point<3> & p1, const Point<3> & p2, double secpoint, + int surfi1, int surfi2, + const EdgePointGeomInfo & ap1, + const EdgePointGeomInfo & ap2, + Point<3> & newp, EdgePointGeomInfo & newgi) const override; + + virtual void PointBetween(const Point<3> & p1, const Point<3> & p2, double secpoint, + int surfi, + const PointGeomInfo & gi1, + const PointGeomInfo & gi2, + Point<3> & newp, PointGeomInfo & newgi) const override; + + int GenerateMesh(shared_ptr & mesh, bool quads, int nx, int ny, bool flip_triangles, const Array>& bbbpts, const Array& bbbnames); + + }; + +} + + + +#endif //SURFACEGEOM From 8046b19b60aee9c52d2965c90cc82a0699ecd86e Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Thu, 25 Jun 2020 18:39:29 +0200 Subject: [PATCH 057/384] fix facets for 3d bbnd elements --- libsrc/include/nginterface_v2_impl.hpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/libsrc/include/nginterface_v2_impl.hpp b/libsrc/include/nginterface_v2_impl.hpp index 6d6d1b85..20fccd2a 100644 --- a/libsrc/include/nginterface_v2_impl.hpp +++ b/libsrc/include/nginterface_v2_impl.hpp @@ -111,7 +111,13 @@ NGX_INLINE DLL_HEADER Ng_Element Ngx_Mesh :: GetElement<1> (size_t nr) const ret.faces.num = 0; ret.faces.ptr = NULL; - if (mesh->GetDimension() == 2) + if (mesh->GetDimension() == 3) + { + ret.facets.num = 0; + ret.facets.base = 0; + ret.facets.ptr = nullptr; + } + else if (mesh->GetDimension() == 2) { ret.facets.num = 1; ret.facets.base = 0; From 88674cd99b659b3a4eaf96a7fc881a861a3db7ea Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Wed, 1 Jul 2020 19:40:44 +0200 Subject: [PATCH 058/384] add some new quad types for boundarylayer, fix problem with multiple boundaries at 1 edge --- libsrc/meshing/boundarylayer.cpp | 125 ++++++++++++++++++++++++++----- 1 file changed, 105 insertions(+), 20 deletions(-) diff --git a/libsrc/meshing/boundarylayer.cpp b/libsrc/meshing/boundarylayer.cpp index 3ce5891a..befe510c 100644 --- a/libsrc/meshing/boundarylayer.cpp +++ b/libsrc/meshing/boundarylayer.cpp @@ -237,13 +237,43 @@ namespace netgen } } - if (!blp.grow_edges) - for(const auto& sel : mesh.LineSegments()) + // project growthvector on surface for inner angles + for(const auto& sel : mesh.SurfaceElements()) + if(!blp.surfid.Contains(sel.GetIndex())) { - bndnodes.Clear(sel[0]); - bndnodes.Clear(sel[1]); + auto n = GetSurfaceNormal(mesh, sel); + for(auto pi : sel.PNums()) + { + if(growthvectors[pi].Length2() == 0.) + continue; + auto& g = growthvectors[pi]; + auto gn = g * n; + auto gg = g * g; + auto nn = n * n; + auto l2 = -2*gn/(gn*gn/gg + nn); + auto l1 = l2 * gn/gg; + auto new_g = g + 0.5 * (l1 * g + l2 * n); + if(new_g * g > 0) + g = new_g; + } } + if (!blp.grow_edges) + { + for(const auto& sel : mesh.LineSegments()) + { + int count = 0; + for(const auto& sel2 : mesh.LineSegments()) + if(((sel[0] == sel2[0] && sel[1] == sel2[1]) || (sel[0] == sel2[1] && sel[1] == sel2[0])) && blp.surfid.Contains(sel2.si)) + count++; + if(count == 1) + { + bndnodes.Clear(sel[0]); + bndnodes.Clear(sel[1]); + } + } + } + // Add additional points into the mesh structure in order to // clone the surface elements. // Also invert the growth vectors so that they point inwards, @@ -266,18 +296,44 @@ namespace netgen // Set them all to "1" to initially activate all segments segsel.Set(); + Array> segmap(nseg); + + // remove double segments (if multiple surfaces come together + // in one edge. If one of them is mapped, keep that one and + // map the others to it. + for(SegmentIndex sei = 0; sei < nseg; sei++) + { + if(!segsel.Test(sei)) continue; + const auto& segi = mesh[sei]; + for(SegmentIndex sej = 0; sej < nseg; sej++) + { + if(sej == sei || !segsel.Test(sej)) continue; + const auto& segj = mesh[sej]; + if(segi[0] == segj[0] && segi[1] == segj[1]) + { + SegmentIndex main, other; + if(blp.surfid.Contains(segi.si)) + { main = sei; other = sej; } + else { main = sej; other = sei; } + segsel.Clear(other); + for(auto& s : segmap[other]) + segmap[main].Append(s); + segmap[other].SetSize(0); + segmap[main].Append(other); + } + } + } PrintMessage(3, "Adding 2D Quad elements on required surfaces..."); if(blp.grow_edges) for(SegmentIndex sei = 0; sei < nseg; sei++) { - auto& segi = mesh[sei]; - // Only go in if the segment is still active, and if both its // surface index is part of the "hit-list" if(segsel.Test(sei)) { + auto& segi = mesh[sei]; if(blp.surfid.Contains(segi.si)) { // clear the bit to indicate that this segment has been processed @@ -368,6 +424,16 @@ namespace netgen mesh.AddSegment(seg_2); } + // in first layer insert new segments adjacent to + // new face + if(layer == 1 && !blp.surfid.Contains(segj.si)) + { + Segment s3 = segj; + s3.si = map_surface_index(segj.si)-1; + s3[0] = mapto[s3[0]]; + s3[1] = mapto[s3[1]]; + mesh.AddSegment(s3); + } // in last layer insert new segments if(layer == blp.heights.Size()) { @@ -509,22 +575,41 @@ namespace netgen int nums[] = { sel[0], sel[1], sel[2], sel[3], mapto[sel[0]], mapto[sel[1]], mapto[sel[2]], mapto[sel[3]] }; - if(classify == 15) + ArrayMem vertices; + switch(classify) { - int vertices[8] = { 0, 1, 2, 3, 4, 5, 6, 7 }; - if(!blp.outside) - { - Swap(vertices[1], vertices[3]); - Swap(vertices[5], vertices[7]); - } - el = Element(HEX); - for(auto i : Range(el.PNums())) - el.PNums()[i] = nums[vertices[i]]; - } - else - { - throw Exception("This type of quad layer not yet implemented!"); + case 6: + { + if(blp.outside) + throw Exception("Type 6 quad outside layer is not yet implemented!"); + el = Element(PRISM); + vertices = {0, 1, 5, 3, 2, 6}; + break; + } + case 9: + { + if(blp.outside) + throw Exception("Type 9 quad outside layer is not yet implemented!"); + el = Element(PRISM); + vertices = { 1, 4, 0, 2, 7, 3 }; + break; + } + case 15: + { + vertices = { 0, 1, 2, 3, 4, 5, 6, 7 }; + if(!blp.outside) + { + Swap(vertices[1], vertices[3]); + Swap(vertices[5], vertices[7]); + } + el = Element(HEX); + break; + } + default: + throw Exception("Type " + ToString(classify) + " for quad layer not yet implemented!"); } + for(auto i : Range(el.PNums())) + el.PNums()[i] = nums[vertices[i]]; } el.SetIndex(blp.new_matnrs[layer-1]); mesh.AddVolumeElement(el); From 7da5cfd3dee0816c476b2d0a30e6f6370a5871af Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Thu, 2 Jul 2020 18:26:16 +0200 Subject: [PATCH 059/384] translate to NGSolve node type in ReadCGNSFile --- libsrc/interface/rw_cgns.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsrc/interface/rw_cgns.cpp b/libsrc/interface/rw_cgns.cpp index 7e55b550..509e96a1 100644 --- a/libsrc/interface/rw_cgns.cpp +++ b/libsrc/interface/rw_cgns.cpp @@ -235,7 +235,7 @@ namespace netgen::cg cg_field_read(fn, base, zone, sol.solution, sol.field_names[fi].c_str(), RealDouble, &imin, &size, &values[0]); sol_names.push_back(sol.field_names[fi]); sol_values.emplace_back(std::move(values)); - sol_locations.push_back(sol.location); + sol_locations.push_back(getNodeType(sol.location)); } } } From fdd718739fd2b8ee6bde7fadbd6ceadbba0da57d Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Fri, 3 Jul 2020 19:51:06 +0200 Subject: [PATCH 060/384] further work on boundarylayers better calculation of growthvector, fix bug with addsegment --- libsrc/meshing/boundarylayer.cpp | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/libsrc/meshing/boundarylayer.cpp b/libsrc/meshing/boundarylayer.cpp index befe510c..04091045 100644 --- a/libsrc/meshing/boundarylayer.cpp +++ b/libsrc/meshing/boundarylayer.cpp @@ -247,14 +247,13 @@ namespace netgen if(growthvectors[pi].Length2() == 0.) continue; auto& g = growthvectors[pi]; - auto gn = g * n; + auto ng = n * g; auto gg = g * g; auto nn = n * n; - auto l2 = -2*gn/(gn*gn/gg + nn); - auto l1 = l2 * gn/gg; - auto new_g = g + 0.5 * (l1 * g + l2 * n); - if(new_g * g > 0) - g = new_g; + if(fabs(ng*ng-nn*gg) < 1e-12 || fabs(ng) < 1e-12) continue; + auto a = -ng*ng/(ng*ng-nn * gg); + auto b = ng*gg/(ng*ng-nn*gg); + g += a*g + b*n; } } @@ -296,11 +295,11 @@ namespace netgen // Set them all to "1" to initially activate all segments segsel.Set(); - Array> segmap(nseg); - // remove double segments (if multiple surfaces come together + // remove double segments (if more than 2 surfaces come together // in one edge. If one of them is mapped, keep that one and // map the others to it. + Array> segmap(nseg); for(SegmentIndex sei = 0; sei < nseg; sei++) { if(!segsel.Test(sei)) continue; @@ -320,6 +319,7 @@ namespace netgen segmap[main].Append(s); segmap[other].SetSize(0); segmap[main].Append(other); + if(other == sei) sej = nseg; } } } @@ -333,7 +333,9 @@ namespace netgen // surface index is part of the "hit-list" if(segsel.Test(sei)) { - auto& segi = mesh[sei]; + // copy here since we will add segments and this would + // invalidate a reference! + auto segi = mesh[sei]; if(blp.surfid.Contains(segi.si)) { // clear the bit to indicate that this segment has been processed @@ -342,7 +344,9 @@ namespace netgen // Find matching segment pair on other surface for(SegmentIndex sej = 0; sej < nseg; sej++) { - auto& segj = mesh[sej]; + // copy here since we will add segments and this would + // invalidate a reference! + auto segj = mesh[sej]; // Find the segment pair on the neighbouring surface element // Identified by: seg1[0] = seg_pair[1] and seg1[1] = seg_pair[0] if(segsel.Test(sej) && ((segi[0] == segj[1]) && (segi[1] == segj[0]))) @@ -456,7 +460,9 @@ namespace netgen mesh.AddSegment(s1); mesh.AddSegment(s2); } - // segi[0] = mapto[segi[0]] not working somehow? + // do not use segi (not even with reference, since + // mesh.AddSegment will resize segment array and + // invalidate reference), this is why we copy it!!! mesh[sei][0] = mapto[segi[0]]; mesh[sei][1] = mapto[segi[1]]; mesh[sej][0] = mapto[segj[0]]; From 8926d93e07fe363d9c82e8ad9ac5bd6c38594348 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20Sch=C3=B6berl?= Date: Sun, 5 Jul 2020 11:15:39 +0200 Subject: [PATCH 061/384] GetTangentialSurfaceIndices was missing for extrusion --- libsrc/csg/extrusion.cpp | 18 ++++++++++++++++++ libsrc/csg/extrusion.hpp | 7 +++++++ 2 files changed, 25 insertions(+) diff --git a/libsrc/csg/extrusion.cpp b/libsrc/csg/extrusion.cpp index 4354bc05..c5518ab8 100644 --- a/libsrc/csg/extrusion.cpp +++ b/libsrc/csg/extrusion.cpp @@ -415,6 +415,14 @@ namespace netgen } + bool ExtrusionFace :: PointInFace (const Point<3> & p, const double eps) const + { + Point<3> hp = p; + Project(hp); + return Dist2(p,hp) < sqr(eps); + } + + void ExtrusionFace :: LineIntersections ( const Point<3> & p, const Vec<3> & v, const double eps, @@ -737,6 +745,16 @@ namespace netgen return PointInSolid(p,eps,NULL); } + void Extrusion :: GetTangentialSurfaceIndices (const Point<3> & p, + NgArray & surfind, double eps) const + { + for (int j = 0; j < faces.Size(); j++) + if (faces[j] -> PointInFace(p, eps)) + if (!surfind.Contains (GetSurfaceId(j))) + surfind.Append (GetSurfaceId(j)); + } + + INSOLID_TYPE Extrusion :: VecInSolid (const Point<3> & p, const Vec<3> & v, double eps) const diff --git a/libsrc/csg/extrusion.hpp b/libsrc/csg/extrusion.hpp index 70a9e4f3..e9680eff 100644 --- a/libsrc/csg/extrusion.hpp +++ b/libsrc/csg/extrusion.hpp @@ -94,6 +94,9 @@ namespace netgen int & after, bool & intersecting ) const; + + bool PointInFace (const Point<3> & p, const double eps) const; + INSOLID_TYPE VecInFace ( const Point<3> & p, const Vec<3> & v, const double eps ) const; @@ -146,6 +149,10 @@ namespace netgen INSOLID_TYPE PointInSolid (const Point<3> & p, double eps, NgArray * const facenums) const; + + virtual void GetTangentialSurfaceIndices (const Point<3> & p, + NgArray & surfind, double eps) const; + virtual INSOLID_TYPE VecInSolid (const Point<3> & p, const Vec<3> & v, double eps) const; From fb13152004ce323353a6d5825b3fb664a22b2940 Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Mon, 13 Jul 2020 18:54:55 +0200 Subject: [PATCH 062/384] create occ geometry from TopoDS_Shape and export constructor this only works if OCC bindings are done using pybind11! --- libsrc/occ/occgeom.cpp | 8 ++++++++ libsrc/occ/occgeom.hpp | 2 ++ libsrc/occ/python_occ.cpp | 2 ++ 3 files changed, 12 insertions(+) diff --git a/libsrc/occ/occgeom.cpp b/libsrc/occ/occgeom.cpp index 91dfb2cf..a3e8ddd3 100644 --- a/libsrc/occ/occgeom.cpp +++ b/libsrc/occ/occgeom.cpp @@ -40,6 +40,14 @@ namespace netgen { + OCCGeometry::OCCGeometry(const TopoDS_Shape& _shape) + { + shape = _shape; + changed = true; + BuildFMap(); + CalcBoundingBox(); + } + string STEP_GetEntityName(const TopoDS_Shape & theShape, STEPCAFControl_Reader * aReader) { const Handle(XSControl_WorkSession)& theSession = aReader->Reader().WS(); diff --git a/libsrc/occ/occgeom.hpp b/libsrc/occ/occgeom.hpp index 447d212f..a491952f 100644 --- a/libsrc/occ/occgeom.hpp +++ b/libsrc/occ/occgeom.hpp @@ -261,6 +261,8 @@ namespace netgen vmap.Clear(); } + OCCGeometry(const TopoDS_Shape& _shape); + Mesh::GEOM_TYPE GetGeomType() const override { return Mesh::GEOM_OCC; } diff --git a/libsrc/occ/python_occ.cpp b/libsrc/occ/python_occ.cpp index a7508c31..a887c0f2 100644 --- a/libsrc/occ/python_occ.cpp +++ b/libsrc/occ/python_occ.cpp @@ -50,6 +50,8 @@ DLL_HEADER void ExportNgOCC(py::module &m) m.attr("occ_version") = OCC_VERSION_COMPLETE; py::class_, NetgenGeometry> (m, "OCCGeometry", R"raw_string(Use LoadOCCGeometry to load the geometry from a *.step file.)raw_string") .def(py::init<>()) + .def(py::init(), py::arg("shape"), + "Create Netgen OCCGeometry from existing TopoDS_Shape") .def(py::init([] (const string& filename) { shared_ptr geo; From ec3d7c3ec934d64519f2fc8e85ad64ee6362f66c Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Tue, 14 Jul 2020 21:30:26 +0200 Subject: [PATCH 063/384] boundarylayer fixes --- libsrc/meshing/boundarylayer.cpp | 76 ++++++++++++++++++++++-------- tests/pytest/test_boundarylayer.py | 38 ++++++++++++--- 2 files changed, 88 insertions(+), 26 deletions(-) diff --git a/libsrc/meshing/boundarylayer.cpp b/libsrc/meshing/boundarylayer.cpp index 04091045..953a96c7 100644 --- a/libsrc/meshing/boundarylayer.cpp +++ b/libsrc/meshing/boundarylayer.cpp @@ -373,9 +373,6 @@ namespace netgen throw Exception("Couldn't find element on other side for " + ToString(segj[0]) + " to " + ToString(segj[1])); const auto& commsel = mesh[pnt_commelem]; - auto surfelem_vect = GetSurfaceNormal(mesh, commsel); - if(blp.outside) - surfelem_vect *= -1; Element2d sel(QUAD); auto seg_p1 = segi[0]; auto seg_p2 = segi[1]; @@ -428,38 +425,78 @@ namespace netgen mesh.AddSegment(seg_2); } - // in first layer insert new segments adjacent to - // new face - if(layer == 1 && !blp.surfid.Contains(segj.si)) - { - Segment s3 = segj; - s3.si = map_surface_index(segj.si)-1; - s3[0] = mapto[s3[0]]; - s3[1] = mapto[s3[1]]; - mesh.AddSegment(s3); - } // in last layer insert new segments if(layer == blp.heights.Size()) { + max_edge_nr++; + if(!blp.surfid.Contains(segj.si)) + { + Segment s3 = segj; + s3.si = map_surface_index(segj.si)-1; + Swap(s3[0], s3[1]); + if(blp.outside) + { + s3[0] = mapto[s3[0]]; + s3[1] = mapto[s3[1]]; + } + else + s3.edgenr = max_edge_nr; + mesh.AddSegment(s3); + } Segment s1 = segi; Segment s2 = segj; - s1.edgenr = ++max_edge_nr; + s1.edgenr = max_edge_nr; s2.edgenr = max_edge_nr; + auto side_surf = domains_to_surf_index[make_tuple(s2.si, blp.new_matnrs[layer-1], mesh.GetFaceDescriptor(s2.si).DomainOut())]; if(blp.surfid.Contains(segj.si)) s2.si = map_surface_index(segj.si); else { - auto side_surf = domains_to_surf_index[make_tuple(s2.si, blp.new_matnrs[layer-1], mesh.GetFaceDescriptor(s2.si).DomainOut())]; if(blp.outside) - s2.si = side_surf; + { + s2.si = side_surf; + } else - segj.si = side_surf; + mesh[sej].si = side_surf; } s1.si = map_surface_index(s1.si); s1.surfnr1 = s1.surfnr2 = s2.surfnr1 = s2.surfnr2 = -1; mesh.AddSegment(s1); mesh.AddSegment(s2); } + + segmap.SetSize(mesh.LineSegments().Size()); + for(auto sei2 : segmap[sei]) + { + auto& s = mesh[sei2]; + if(blp.outside && layer == blp.heights.Size()) + { + if(blp.surfid.Contains(s.si)) + s.si = map_surface_index(s.si); + s.edgenr = max_edge_nr; + } + else + { + s[0] = mapto[s[0]]; + s[1] = mapto[s[1]]; + } + } + for(auto sej2 : segmap[sej]) + { + auto& s = mesh[sej2]; + if(blp.outside && layer == blp.heights.Size()) + { + if(blp.surfid.Contains(s.si)) + s.si = map_surface_index(s.si); + s.edgenr = max_edge_nr; + } + else + { + s[0] = mapto[s[0]]; + s[1] = mapto[s[1]]; + } + } + // do not use segi (not even with reference, since // mesh.AddSegment will resize segment array and // invalidate reference), this is why we copy it!!! @@ -477,6 +514,8 @@ namespace netgen // if necessary map them for(SegmentIndex sej = 0; sej Date: Wed, 15 Jul 2020 13:31:16 +0200 Subject: [PATCH 064/384] Fix CGNS reader for 2d meshes, cleanup --- libsrc/interface/rw_cgns.cpp | 165 ++++++++++++++++++++--------------- 1 file changed, 94 insertions(+), 71 deletions(-) diff --git a/libsrc/interface/rw_cgns.cpp b/libsrc/interface/rw_cgns.cpp index 509e96a1..05761577 100644 --- a/libsrc/interface/rw_cgns.cpp +++ b/libsrc/interface/rw_cgns.cpp @@ -176,9 +176,11 @@ namespace netgen::cg { ZoneType_t zone_type; int fn, base, zone; - int nv, ne, first_mat, first_bc; - Array materials; - Array boundaries; + int first_index_1d, first_index_2d, first_index_3d; + int nv=0, ne_1d=0, ne_2d=0, ne_3d=0; + + Array names_1d, names_2d, names_3d; + string name; cgsize_t size[3]; @@ -200,7 +202,7 @@ namespace netgen::cg solutions[si] = Solution{fn, base, zone, si+1}; } - void ReadSolutions( std::vector & sol_names, std::vector> & sol_values, std::vector & sol_locations ) + void ReadSolutions( int meshdim, std::vector & sol_names, std::vector> & sol_values, std::vector & sol_locations ) { static Timer tall("CGNS::ReadSolutions"); RegionTimer rtall(tall); for (auto & sol : solutions) @@ -208,6 +210,7 @@ namespace netgen::cg for (auto fi : Range(sol.field_names.Size())) { cgsize_t size = sol.n_points; + size=0; // TODO: check if sol.point_type is a list or range, and handle appropriately if(size==0) { switch(sol.location) @@ -216,7 +219,7 @@ namespace netgen::cg size = nv; break; case CellCenter: - size = ne; + size = (meshdim == 3 ? ne_3d : ne_2d); break; case FaceCenter: case IFaceCenter: @@ -228,7 +231,6 @@ namespace netgen::cg } } - size = size==0 ? nv : size; auto values = Array(size); cgsize_t imin = 1UL; @@ -244,9 +246,9 @@ namespace netgen::cg { static Timer tall("CGNS::ReadMesh-Zone"); RegionTimer rtall(tall); static Timer tsection("CGNS::ReadMesh-Section"); - first_mat = mesh.GetRegionNamesCD(0).Size(); - first_bc = mesh.GetRegionNamesCD(1).Size(); - ne = 0; + first_index_1d = mesh.GetRegionNamesCD(2).Size(); + first_index_2d = mesh.GetRegionNamesCD(1).Size(); + first_index_3d = mesh.GetRegionNamesCD(0).Size(); Array x(nv), y(nv), z(nv); cgsize_t imin=1; @@ -276,8 +278,10 @@ namespace netgen::cg int nsections; cg_nsections(fn, base, zone, &nsections); - int bc = first_bc; - int material = first_mat; + int index_1d = first_index_1d; + int index_2d = first_index_2d; + int index_3d = first_index_3d; + for (auto section : Range(1,nsections+1)) { RegionTimer rtsection(tsection); @@ -288,8 +292,6 @@ namespace netgen::cg cg_section_read(fn, base, zone, section, sec_name, &type, &start, &end, &nbndry, &parent_flag); PrintMessage(4, "Read section ", section, " with name ", sec_name, " and element type ", cg_ElementTypeName(type)); - if(name == "Coil" && string(sec_name) == "Top") - continue; string ngname{sec_name}; @@ -300,6 +302,7 @@ namespace netgen::cg if(type==MIXED) { + bool have_1d_elements = false; bool have_2d_elements = false; bool have_3d_elements = false; @@ -327,40 +330,50 @@ namespace netgen::cg if(dim==1) { + if(!have_1d_elements) + { + index_1d++; + have_1d_elements = true; + mesh.AddEdgeDescriptor(EdgeDescriptor{}); + names_1d.Append(ngname); + } auto el = ReadCGNSElement1D(type, vertices.Range(vi, vertices.Size())); + el.si = index_1d; mesh.AddSegment(el); vi += el.GetNP(); + ne_1d++; } if(dim==2) { if(!have_2d_elements) { - bc++; + index_2d++; have_2d_elements = true; - mesh.AddFaceDescriptor(FaceDescriptor(bc, 1, 0, 1)); - mesh.SetBCName(bc-1, ngname); + mesh.AddFaceDescriptor(FaceDescriptor(index_2d, 1, 0, 1)); + names_2d.Append(ngname); } auto el = ReadCGNSElement2D(type, vertices.Range(vi, vertices.Size())); - el.SetIndex(bc); + el.SetIndex(index_2d); mesh.AddSurfaceElement(el); vi += el.GetNP(); + ne_2d++; } if(dim==3) { if(!have_3d_elements) { - material++; + index_3d++; have_3d_elements = true; - mesh.SetMaterial(material, ngname); + names_3d.Append(ngname); } auto el = ReadCGNSElement3D(type, vertices.Range(vi, vertices.Size())); - el.SetIndex(material); + el.SetIndex(index_3d); mesh.AddVolumeElement(el); vi += el.GetNP(); - ne++; + ne_3d++; } } } @@ -381,48 +394,78 @@ namespace netgen::cg if(dim==1) { + index_1d++; + mesh.AddEdgeDescriptor(EdgeDescriptor{}); + names_1d.Append(ngname); for(auto i : Range(ne_section)) { auto el = ReadCGNSElement1D(type, vertices.Range(np*i, np*(i+1))); + el.si = index_1d; mesh.AddSegment(el); } + ne_1d += ne_section; } if(dim==2) { - bc++; - mesh.AddFaceDescriptor(FaceDescriptor(bc, 1, 0, 1)); + index_2d++; + mesh.AddFaceDescriptor(FaceDescriptor(index_2d, 1, 0, 1)); + names_2d.Append(ngname); for(auto i : Range(ne_section)) { auto el = ReadCGNSElement2D(type, vertices.Range(np*i, np*(i+1))); - el.SetIndex(bc); + el.SetIndex(index_2d); mesh.AddSurfaceElement(el); } - mesh.SetBCName(bc-1, ngname); + ne_2d += ne_section; } if(dim==3) { - material++; + index_3d++; + names_3d.Append(ngname); for(auto i : Range(ne_section)) { auto el = ReadCGNSElement3D(type, vertices.Range(np*i, np*(i+1))); - el.SetIndex(material); + el.SetIndex(index_3d); mesh.AddVolumeElement(el); } - mesh.SetMaterial(material, ngname); - ne += ne_section; + ne_3d += ne_section; } } } } + + void SetNames( Mesh & mesh ) + { + if(mesh.GetDimension() == 2) + { + for (auto i : Range(names_1d.Size())) + mesh.SetBCName(first_index_1d + i, names_1d[i]); + + for (auto i : Range(names_2d.Size())) + mesh.SetMaterial(first_index_2d + i +1, names_2d[i]); + } + else + { + for (auto i : Range(names_1d.Size())) + mesh.SetCD2Name(first_index_1d + i +1, names_1d[i]); + + for (auto i : Range(names_2d.Size())) + mesh.SetBCName(first_index_2d + i, names_2d[i]); + + for (auto i : Range(names_3d.Size())) + mesh.SetMaterial(first_index_3d + i +1, names_3d[i]); + } + } }; } namespace netgen { - void ReadCGNSMesh (Mesh & mesh, const string & filename) + int ReadCGNSMesh (Mesh & mesh, const string & filename, Array> & zones) { + mesh.SetDimension(3); static Timer tall("CGNS::ReadMesh"); RegionTimer rtall(tall); int fn; cg_open(filename.c_str(),CG_MODE_READ,&fn); @@ -431,9 +474,6 @@ namespace netgen int nzones; cg_nzones(fn, base, &nzones); - int bc = 0; - int material = 0; - int n_vertices = 0; for (auto zi : Range(1, nzones+1)) { @@ -454,58 +494,41 @@ namespace netgen PrintMessage(2, "skipping zone with type ", cg_ZoneTypeName(zone_type) ); continue; } - cg::Zone zone(fn, base, zi); - zone.ReadMesh( mesh, points ); + auto zone = make_unique(fn, base, zi); + zone->ReadMesh( mesh, points ); + zones.Append(std::move(zone)); } + + if(mesh.GetNE() == 0) + mesh.SetDimension(2); + + for (auto & zone : zones) + zone->SetNames(mesh); + return fn; + } + + void ReadCGNSMesh (Mesh & mesh, const string & filename) + { + Array> zones; + int fn = ReadCGNSMesh(mesh, filename, zones); + cg_close(fn); } // Reads mesh and solutions of .csns file tuple, vector, vector>, vector> ReadCGNSFile(string filename, int base) { static Timer tall("CGNS::ReadFile"); RegionTimer rtall(tall); - int fn; - cg_open(filename.c_str(),CG_MODE_READ,&fn); - - int nbases; - cg_nbases(fn, &nbases); - - int nzones; - cg_nzones(fn, base, &nzones); auto mesh = make_shared(); - - int bc = 0; - int material = 0; - + Array> zones; + int fn = ReadCGNSMesh(*mesh, filename, zones); std::vector names; std::vector> values; std::vector locations; - int n_vertices = 0; - for (auto zi : Range(1, nzones+1)) - { - int size[3]; - char name[100]; - cg_zone_read(fn,base,zi, name, size); - n_vertices += size[0]; - } - - cg::PointTable points(2*n_vertices); - - for (auto zi : Range(1, nzones+1)) - { - ZoneType_t zone_type; - cg_zone_type(fn, base, zi, &zone_type); - if(zone_type != Unstructured ) - { - clog << "skipping zone with type " << cg_ZoneTypeName(zone_type) << endl; - continue; - } - cg::Zone zone(fn, base, zi); - zone.ReadMesh( *mesh, points ); - zone.ReadSolutions( names, values, locations ); - } + for (auto & zone : zones) + zone->ReadSolutions( mesh->GetDimension(), names, values, locations ); cg_close(fn); return std::make_tuple(mesh, names, values, locations); From e17aa88cad2c37039e93958599a84ed9107f4c97 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Wed, 15 Jul 2020 16:21:51 +0200 Subject: [PATCH 065/384] set signal handlers only if NG_BACKTRACE is set --- libsrc/core/exception.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/libsrc/core/exception.cpp b/libsrc/core/exception.cpp index df750050..b89d721e 100644 --- a/libsrc/core/exception.cpp +++ b/libsrc/core/exception.cpp @@ -217,9 +217,12 @@ static void ngcore_signal_handler(int sig) // register signal handler when library is loaded static bool dummy = []() { - signal(SIGABRT, ngcore_signal_handler); - signal(SIGILL, ngcore_signal_handler); - signal(SIGSEGV, ngcore_signal_handler); + if(getenv("NG_BACKTRACE")) + { + signal(SIGABRT, ngcore_signal_handler); + signal(SIGILL, ngcore_signal_handler); + signal(SIGSEGV, ngcore_signal_handler); + } return true; }(); From ce8ba71f33ce6a4eeb4d839026087f15b1fb31c1 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Wed, 15 Jul 2020 17:26:39 +0000 Subject: [PATCH 066/384] Fix SwapImprove --- libsrc/meshing/improve3.cpp | 9 +- tests/pytest/results.json | 558 ++++++++++++++++++------------------ 2 files changed, 286 insertions(+), 281 deletions(-) diff --git a/libsrc/meshing/improve3.cpp b/libsrc/meshing/improve3.cpp index d9cc3534..78ef49f9 100644 --- a/libsrc/meshing/improve3.cpp +++ b/libsrc/meshing/improve3.cpp @@ -2015,6 +2015,8 @@ double MeshOptimize3d :: SwapImproveEdge (Mesh & mesh, OPTIMIZEGOAL goal, } } + bool have_bad_element = false; + for (ElementIndex ei : hasbothpoints) { if (mesh[ei].GetType () != TET) @@ -2037,10 +2039,13 @@ double MeshOptimize3d :: SwapImproveEdge (Mesh & mesh, OPTIMIZEGOAL goal, if ((goal == OPT_LEGAL) && mesh.LegalTet (mesh[ei]) && - CalcBad (mesh.Points(), mesh[ei], 0) < 1e3) - return 0.0; + CalcBad (mesh.Points(), mesh[ei], 0) >= 1e3) + have_bad_element = true; } + if ((goal == OPT_LEGAL) && !have_bad_element) + return 0.0; + int nsuround = hasbothpoints.Size(); int mattyp = mesh[hasbothpoints[0]].GetIndex(); diff --git a/tests/pytest/results.json b/tests/pytest/results.json index b9f3f047..9b6540a7 100644 --- a/tests/pytest/results.json +++ b/tests/pytest/results.json @@ -110,7 +110,7 @@ { "angles_tet": [ 14.829, - 145.34 + 146.41 ], "angles_trig": [ 16.491, @@ -118,9 +118,9 @@ ], "ne1d": 94, "ne2d": 114, - "ne3d": 121, - "quality_histogram": "[0, 0, 0, 0, 1, 2, 4, 9, 17, 14, 11, 12, 10, 7, 11, 4, 2, 14, 3, 0]", - "total_badness": 227.92261008 + "ne3d": 122, + "quality_histogram": "[0, 0, 0, 0, 1, 2, 4, 9, 19, 14, 12, 10, 10, 7, 11, 4, 2, 14, 3, 0]", + "total_badness": 231.46662286 }, { "angles_tet": [ @@ -293,33 +293,33 @@ }, { "angles_tet": [ - 15.271, - 159.02 + 13.26, + 163.45 ], "angles_trig": [ - 14.076, - 146.64 + 11.907, + 152.58 ], "ne1d": 32, "ne2d": 220, - "ne3d": 642, - "quality_histogram": "[0, 0, 0, 0, 4, 22, 41, 45, 52, 48, 42, 42, 63, 64, 57, 33, 39, 45, 37, 8]", - "total_badness": 1182.99704 + "ne3d": 556, + "quality_histogram": "[0, 0, 0, 4, 7, 14, 27, 33, 41, 29, 37, 47, 34, 50, 41, 51, 63, 38, 30, 10]", + "total_badness": 997.95710204 }, { "angles_tet": [ - 2.7569, - 173.39 + 2.8811, + 172.75 ], "angles_trig": [ - 7.6422, - 156.83 + 9.0948, + 156.22 ], "ne1d": 48, "ne2d": 428, - "ne3d": 811, - "quality_histogram": "[0, 8, 32, 34, 32, 51, 46, 63, 86, 81, 63, 72, 59, 44, 46, 24, 27, 24, 15, 4]", - "total_badness": 2131.9115363 + "ne3d": 770, + "quality_histogram": "[2, 11, 24, 35, 27, 40, 36, 49, 76, 95, 61, 81, 68, 31, 52, 32, 17, 19, 12, 2]", + "total_badness": 2061.8554811 }, { "angles_tet": [ @@ -462,18 +462,18 @@ "cubeandring.geo": [ { "angles_tet": [ - 4.093, - 171.18 + 5.2065, + 170.27 ], "angles_trig": [ - 12.541, - 150.46 + 10.96, + 154.62 ], "ne1d": 262, "ne2d": 726, - "ne3d": 2186, - "quality_histogram": "[0, 4, 11, 34, 76, 101, 133, 102, 83, 52, 61, 79, 114, 196, 255, 258, 257, 227, 114, 29]", - "total_badness": 4154.7434704 + "ne3d": 2153, + "quality_histogram": "[0, 5, 20, 35, 79, 117, 112, 108, 75, 47, 53, 85, 111, 177, 250, 290, 240, 204, 118, 27]", + "total_badness": 4183.5255584 }, { "angles_tet": [ @@ -502,23 +502,23 @@ "ne1d": 190, "ne2d": 300, "ne3d": 631, - "quality_histogram": "[0, 0, 0, 0, 1, 0, 0, 3, 8, 27, 48, 60, 69, 107, 85, 89, 64, 48, 20, 2]", - "total_badness": 943.22810332 + "quality_histogram": "[0, 0, 0, 0, 1, 0, 0, 3, 8, 27, 48, 61, 68, 107, 85, 89, 63, 49, 20, 2]", + "total_badness": 943.22430902 }, { "angles_tet": [ - 5.1018, - 167.98 + 5.4026, + 168.34 ], "angles_trig": [ - 12.696, + 13.552, 150.46 ], "ne1d": 262, "ne2d": 726, - "ne3d": 2080, - "quality_histogram": "[0, 2, 6, 20, 50, 80, 113, 90, 72, 47, 38, 75, 95, 179, 262, 272, 286, 224, 135, 34]", - "total_badness": 3667.9320382 + "ne3d": 2048, + "quality_histogram": "[0, 2, 10, 18, 56, 101, 108, 97, 63, 36, 41, 60, 100, 164, 255, 284, 287, 195, 135, 36]", + "total_badness": 3675.3946288 }, { "angles_tet": [ @@ -533,7 +533,7 @@ "ne2d": 1412, "ne3d": 7670, "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 2, 7, 36, 112, 284, 477, 845, 1308, 1555, 1517, 1168, 359]", - "total_badness": 9545.7928464 + "total_badness": 9545.7933664 }, { "angles_tet": [ @@ -661,18 +661,18 @@ }, { "angles_tet": [ - 20.47, - 141.07 + 19.437, + 141.17 ], "angles_trig": [ - 17.455, - 137.29 + 17.771, + 130.84 ], "ne1d": 64, "ne2d": 642, - "ne3d": 3261, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 2, 17, 24, 62, 115, 220, 353, 475, 545, 510, 445, 318, 143, 32]", - "total_badness": 4608.5480688 + "ne3d": 3305, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 1, 11, 21, 62, 135, 236, 368, 452, 577, 512, 439, 311, 151, 29]", + "total_badness": 4674.6678046 }, { "angles_tet": [ @@ -845,33 +845,33 @@ }, { "angles_tet": [ - 19.3, - 149.07 + 24.676, + 151.98 ], "angles_trig": [ - 23.799, - 122.37 + 24.811, + 126.7 ], "ne1d": 24, "ne2d": 66, - "ne3d": 71, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 2, 2, 4, 9, 1, 5, 3, 3, 3, 2, 9, 24, 3, 1]", - "total_badness": 108.79228828 + "ne3d": 70, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 1, 0, 6, 5, 5, 2, 6, 5, 3, 5, 14, 17, 1, 0]", + "total_badness": 105.64076027 }, { "angles_tet": [ - 14.383, - 158.73 + 15.925, + 157.39 ], "angles_trig": [ - 12.296, - 144.06 + 17.814, + 127.45 ], "ne1d": 36, "ne2d": 152, - "ne3d": 515, - "quality_histogram": "[0, 0, 0, 1, 2, 12, 25, 45, 55, 55, 63, 44, 38, 41, 26, 30, 42, 16, 13, 7]", - "total_badness": 981.48109509 + "ne3d": 381, + "quality_histogram": "[0, 0, 0, 0, 0, 9, 13, 18, 26, 25, 30, 29, 42, 32, 39, 28, 41, 21, 22, 6]", + "total_badness": 648.79536841 }, { "angles_tet": [ @@ -941,14 +941,14 @@ 167.27 ], "angles_trig": [ - 10.973, + 13.416, 150.52 ], "ne1d": 48, "ne2d": 142, - "ne3d": 162, - "quality_histogram": "[0, 0, 2, 7, 26, 32, 17, 2, 0, 2, 0, 1, 2, 5, 6, 15, 15, 13, 17, 0]", - "total_badness": 437.74460755 + "ne3d": 150, + "quality_histogram": "[0, 0, 0, 5, 27, 32, 16, 4, 0, 2, 1, 1, 4, 5, 3, 17, 16, 7, 10, 0]", + "total_badness": 409.78409193 }, { "angles_tet": [ @@ -1014,33 +1014,33 @@ }, { "angles_tet": [ - 4.2159, - 171.02 + 5.1577, + 170.71 ], "angles_trig": [ - 7.6756, - 159.68 + 8.073, + 161.81 ], "ne1d": 0, "ne2d": 192, - "ne3d": 957, - "quality_histogram": "[0, 21, 76, 109, 128, 111, 100, 84, 77, 55, 62, 31, 32, 22, 10, 15, 8, 10, 4, 2]", - "total_badness": 3582.099151 + "ne3d": 748, + "quality_histogram": "[0, 5, 41, 63, 100, 92, 74, 71, 54, 49, 43, 43, 23, 20, 20, 20, 10, 5, 12, 3]", + "total_badness": 2470.4393077 }, { "angles_tet": [ - 19.919, - 134.24 + 19.777, + 131.46 ], "angles_trig": [ - 19.054, - 114.7 + 20.139, + 112.74 ], "ne1d": 0, "ne2d": 394, "ne3d": 597, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 2, 6, 29, 49, 60, 87, 92, 86, 82, 48, 33, 15, 8]", - "total_badness": 899.55007686 + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 2, 6, 29, 41, 61, 90, 98, 81, 81, 55, 29, 17, 7]", + "total_badness": 896.10180497 }, { "angles_tet": [ @@ -1091,18 +1091,18 @@ "ellipticcone.geo": [ { "angles_tet": [ - 17.698, + 17.699, 148.03 ], "angles_trig": [ - 23.433, + 23.943, 122.76 ], "ne1d": 174, "ne2d": 1562, - "ne3d": 5188, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 1, 1, 9, 31, 100, 197, 340, 544, 700, 933, 940, 757, 460, 175]", - "total_badness": 6822.0657356 + "ne3d": 5212, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 1, 1, 8, 32, 89, 187, 328, 534, 719, 937, 969, 775, 458, 174]", + "total_badness": 6834.3167615 }, { "angles_tet": [ @@ -1121,33 +1121,33 @@ }, { "angles_tet": [ - 16.571, + 16.597, 149.96 ], "angles_trig": [ - 18.137, + 18.553, 135.0 ], "ne1d": 130, "ne2d": 864, - "ne3d": 1653, - "quality_histogram": "[0, 0, 0, 0, 0, 2, 9, 29, 44, 46, 61, 116, 147, 195, 200, 234, 270, 172, 100, 28]", - "total_badness": 2389.4865072 + "ne3d": 1652, + "quality_histogram": "[0, 0, 0, 0, 0, 2, 12, 28, 40, 57, 56, 113, 146, 183, 206, 245, 268, 166, 103, 27]", + "total_badness": 2393.1339621 }, { "angles_tet": [ - 21.001, - 144.04 + 21.766, + 144.03 ], "angles_trig": [ - 25.698, + 25.696, 119.99 ], "ne1d": 174, "ne2d": 1562, - "ne3d": 5007, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 1, 2, 10, 50, 105, 242, 409, 648, 901, 1007, 887, 539, 206]", - "total_badness": 6381.0431998 + "ne3d": 5072, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 4, 11, 54, 93, 228, 440, 641, 935, 1026, 892, 544, 204]", + "total_badness": 6463.5570559 }, { "angles_tet": [ @@ -1367,7 +1367,7 @@ "frame.step": [ { "angles_tet": [ - 2.9116, + 2.9095, 171.1 ], "angles_trig": [ @@ -1376,9 +1376,9 @@ ], "ne1d": 10108, "ne2d": 30160, - "ne3d": 152872, - "quality_histogram": "[0, 3, 1, 3, 6, 18, 67, 161, 549, 1308, 2949, 5900, 10578, 16512, 21632, 25909, 26394, 22816, 14332, 3734]", - "total_badness": 202698.59306 + "ne3d": 152987, + "quality_histogram": "[0, 3, 1, 3, 6, 20, 57, 149, 535, 1257, 2919, 5827, 10443, 16376, 21793, 26060, 26579, 22897, 14346, 3716]", + "total_badness": 202618.94822 }, { "angles_tet": [ @@ -1391,13 +1391,13 @@ ], "ne1d": 5988, "ne2d": 11102, - "ne3d": 29165, - "quality_histogram": "[3, 4, 7, 13, 24, 41, 117, 235, 718, 979, 1564, 2453, 3072, 3948, 4334, 4219, 3348, 2423, 1351, 312]", - "total_badness": 43278.945822 + "ne3d": 29317, + "quality_histogram": "[3, 4, 5, 8, 16, 44, 120, 246, 699, 1024, 1561, 2491, 3110, 3894, 4329, 4296, 3374, 2408, 1353, 332]", + "total_badness": 43465.268618 }, { "angles_tet": [ - 2.1657, + 2.5792, 174.11 ], "angles_trig": [ @@ -1406,15 +1406,15 @@ ], "ne1d": 9622, "ne2d": 23964, - "ne3d": 80724, - "quality_histogram": "[1, 16, 3, 19, 17, 40, 93, 222, 516, 1095, 2417, 4595, 7465, 10279, 12687, 13138, 11850, 9165, 5675, 1431]", - "total_badness": 111634.58051 + "ne3d": 80994, + "quality_histogram": "[2, 14, 4, 20, 18, 40, 94, 224, 488, 1114, 2412, 4540, 7490, 10250, 12758, 13185, 12021, 9204, 5660, 1456]", + "total_badness": 111934.48598 } ], "hinge.stl": [ { "angles_tet": [ - 20.946, + 21.248, 144.42 ], "angles_trig": [ @@ -1424,23 +1424,23 @@ "ne1d": 456, "ne2d": 1220, "ne3d": 1986, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 7, 20, 39, 70, 124, 179, 243, 300, 298, 263, 259, 143, 41]", - "total_badness": 2750.7798523 + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 8, 20, 39, 66, 127, 177, 243, 307, 299, 259, 259, 141, 41]", + "total_badness": 2751.3290713 }, { "angles_tet": [ - 7.6272, + 7.7862, 161.84 ], "angles_trig": [ - 9.1007, + 9.6143, 148.89 ], "ne1d": 298, "ne2d": 610, - "ne3d": 817, - "quality_histogram": "[0, 0, 1, 11, 8, 5, 21, 16, 43, 41, 72, 88, 107, 100, 84, 87, 52, 50, 28, 3]", - "total_badness": 1409.8967045 + "ne3d": 788, + "quality_histogram": "[0, 0, 1, 10, 9, 4, 22, 15, 39, 41, 68, 84, 103, 97, 84, 85, 48, 49, 25, 4]", + "total_badness": 1361.2509309 }, { "angles_tet": [ @@ -1483,24 +1483,24 @@ ], "ne1d": 722, "ne2d": 2866, - "ne3d": 6697, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 1, 2, 26, 30, 56, 167, 331, 645, 892, 1039, 1173, 1196, 881, 258]", - "total_badness": 8588.7853201 + "ne3d": 6700, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 1, 2, 22, 29, 52, 170, 325, 637, 877, 1046, 1169, 1237, 870, 263]", + "total_badness": 8579.1803793 }, { "angles_tet": [ 20.701, - 142.89 + 140.94 ], "angles_trig": [ 22.443, - 124.89 + 122.89 ], "ne1d": 1862, "ne2d": 19474, - "ne3d": 136597, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 1, 12, 54, 288, 870, 2618, 6513, 13052, 21346, 28986, 31108, 23898, 7851]", - "total_badness": 166108.75934 + "ne3d": 136555, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 1, 12, 59, 278, 860, 2542, 6422, 13021, 21252, 29142, 31120, 24008, 7838]", + "total_badness": 165971.00359 } ], "lense.in2d": [ @@ -1709,19 +1709,19 @@ 149.67 ], "angles_trig": [ - 14.887, + 15.246, 137.87 ], "ne1d": 2746, "ne2d": 13866, - "ne3d": 29396, - "quality_histogram": "[0, 0, 0, 0, 14, 15, 38, 137, 372, 851, 1456, 2307, 3270, 4307, 4196, 3746, 3316, 2685, 1975, 711]", - "total_badness": 42211.73971 + "ne3d": 29391, + "quality_histogram": "[0, 0, 0, 0, 13, 14, 37, 138, 377, 848, 1450, 2328, 3278, 4286, 4195, 3745, 3323, 2685, 1964, 710]", + "total_badness": 42208.591965 }, { "angles_tet": [ 11.183, - 158.43 + 153.89 ], "angles_trig": [ 12.194, @@ -1729,9 +1729,9 @@ ], "ne1d": 4106, "ne2d": 27994, - "ne3d": 70594, - "quality_histogram": "[0, 0, 0, 1, 34, 79, 184, 352, 684, 1479, 2553, 4149, 6716, 9292, 10342, 10582, 9852, 7683, 4825, 1787]", - "total_badness": 98915.787673 + "ne3d": 70783, + "quality_histogram": "[0, 0, 0, 1, 30, 72, 170, 340, 660, 1449, 2616, 4104, 6681, 9272, 10482, 10764, 9861, 7627, 4870, 1784]", + "total_badness": 99055.647638 } ], "manyholes2.geo": [ @@ -1746,9 +1746,9 @@ ], "ne1d": 10202, "ne2d": 55380, - "ne3d": 128326, - "quality_histogram": "[0, 0, 0, 0, 4, 29, 80, 239, 718, 1909, 4473, 7696, 11673, 17533, 18499, 18373, 17274, 15234, 10928, 3664]", - "total_badness": 176317.23115 + "ne3d": 128240, + "quality_histogram": "[0, 0, 0, 0, 4, 29, 79, 237, 725, 1935, 4437, 7722, 11695, 17431, 18582, 18325, 17276, 15158, 10938, 3667]", + "total_badness": 176228.44994 } ], "matrix.geo": [ @@ -1815,7 +1815,7 @@ { "angles_tet": [ 12.758, - 147.69 + 148.17 ], "angles_trig": [ 15.825, @@ -1823,9 +1823,9 @@ ], "ne1d": 248, "ne2d": 2324, - "ne3d": 16276, - "quality_histogram": "[0, 0, 0, 0, 0, 5, 22, 54, 116, 179, 301, 610, 975, 1512, 2111, 2585, 2741, 2659, 1833, 573]", - "total_badness": 21483.905479 + "ne3d": 16371, + "quality_histogram": "[0, 0, 0, 0, 0, 5, 22, 53, 115, 192, 297, 621, 1022, 1479, 2137, 2601, 2778, 2625, 1890, 534]", + "total_badness": 21627.026306 }, { "angles_tet": [ @@ -1963,23 +1963,23 @@ "ne1d": 134, "ne2d": 288, "ne3d": 528, - "quality_histogram": "[0, 0, 0, 2, 4, 2, 4, 3, 16, 24, 36, 41, 54, 70, 68, 73, 59, 47, 24, 1]", - "total_badness": 813.79298254 + "quality_histogram": "[0, 0, 0, 2, 4, 2, 4, 3, 16, 24, 36, 42, 54, 69, 66, 74, 61, 46, 24, 1]", + "total_badness": 813.76674756 }, { "angles_tet": [ - 21.121, - 136.02 + 20.704, + 143.31 ], "angles_trig": [ - 24.392, + 24.375, 116.27 ], "ne1d": 194, "ne2d": 594, - "ne3d": 1699, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 1, 3, 16, 27, 60, 126, 203, 248, 264, 314, 243, 151, 43]", - "total_badness": 2248.5537373 + "ne3d": 1693, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 1, 5, 14, 28, 54, 137, 197, 250, 262, 308, 248, 149, 40]", + "total_badness": 2242.4690855 }, { "angles_tet": [ @@ -2019,44 +2019,44 @@ 150.16 ], "angles_trig": [ - 18.679, - 133.12 + 18.736, + 133.1 ], "ne1d": 344, "ne2d": 1136, - "ne3d": 3263, - "quality_histogram": "[0, 0, 0, 0, 1, 4, 15, 26, 53, 90, 178, 259, 351, 445, 457, 447, 406, 297, 185, 49]", - "total_badness": 4746.5378667 + "ne3d": 3269, + "quality_histogram": "[0, 0, 0, 0, 2, 4, 13, 24, 57, 92, 181, 260, 351, 430, 482, 454, 417, 280, 179, 43]", + "total_badness": 4762.4191481 }, { "angles_tet": [ - 9.7417, - 164.57 + 12.301, + 162.28 ], "angles_trig": [ - 12.303, - 141.6 + 14.582, + 141.01 ], "ne1d": 160, "ne2d": 286, - "ne3d": 568, - "quality_histogram": "[0, 0, 0, 2, 9, 12, 20, 25, 31, 69, 59, 78, 60, 40, 38, 40, 34, 33, 14, 4]", - "total_badness": 1044.7873254 + "ne3d": 590, + "quality_histogram": "[0, 0, 0, 0, 6, 10, 15, 24, 40, 62, 65, 67, 64, 47, 50, 45, 38, 42, 12, 3]", + "total_badness": 1045.1530377 }, { "angles_tet": [ - 13.063, - 161.0 + 12.731, + 162.52 ], "angles_trig": [ - 16.741, - 141.37 + 15.335, + 148.34 ], "ne1d": 232, "ne2d": 598, - "ne3d": 1523, - "quality_histogram": "[0, 0, 0, 1, 7, 20, 34, 48, 65, 111, 135, 155, 165, 189, 171, 134, 132, 89, 52, 15]", - "total_badness": 2538.6647915 + "ne3d": 1383, + "quality_histogram": "[0, 0, 0, 1, 13, 17, 35, 53, 69, 92, 121, 143, 146, 153, 154, 121, 115, 84, 52, 14]", + "total_badness": 2341.0219936 }, { "angles_tet": [ @@ -2064,14 +2064,14 @@ 150.16 ], "angles_trig": [ - 19.4, - 134.3 + 19.085, + 134.23 ], "ne1d": 344, "ne2d": 1136, - "ne3d": 3233, - "quality_histogram": "[0, 0, 0, 0, 1, 4, 12, 23, 48, 81, 149, 226, 335, 430, 473, 436, 439, 333, 186, 57]", - "total_badness": 4637.4815537 + "ne3d": 3234, + "quality_histogram": "[0, 0, 0, 0, 2, 4, 12, 25, 48, 85, 148, 219, 353, 420, 468, 466, 428, 322, 182, 52]", + "total_badness": 4649.5043488 }, { "angles_tet": [ @@ -2111,34 +2111,34 @@ 166.97 ], "angles_trig": [ - 1.8776, + 3.5084, 158.16 ], "ne1d": 886, "ne2d": 2592, - "ne3d": 8251, - "quality_histogram": "[4, 9, 37, 43, 43, 52, 43, 48, 107, 147, 263, 410, 617, 958, 1225, 1264, 1209, 1019, 602, 151]", - "total_badness": 12329.19667 + "ne3d": 8268, + "quality_histogram": "[4, 9, 33, 42, 41, 54, 43, 47, 100, 142, 258, 402, 641, 938, 1253, 1305, 1193, 1022, 588, 153]", + "total_badness": 12309.108485 }, { "angles_tet": [ - 1.0836, + 1.0841, 174.05 ], "angles_trig": [ - 2.5669, + 3.4703, 170.0 ], "ne1d": 570, "ne2d": 1202, - "ne3d": 1831, - "quality_histogram": "[2, 29, 38, 60, 65, 77, 105, 141, 152, 176, 189, 161, 156, 135, 118, 80, 71, 48, 24, 4]", - "total_badness": 4620.6249923 + "ne3d": 1823, + "quality_histogram": "[2, 22, 36, 57, 66, 78, 105, 136, 163, 183, 187, 160, 150, 143, 114, 76, 69, 47, 25, 4]", + "total_badness": 4525.5906501 }, { "angles_tet": [ 1.1033, - 172.28 + 172.29 ], "angles_trig": [ 3.728, @@ -2146,39 +2146,39 @@ ], "ne1d": 724, "ne2d": 1730, - "ne3d": 3241, - "quality_histogram": "[3, 15, 33, 52, 50, 37, 49, 80, 128, 163, 207, 267, 344, 390, 425, 377, 308, 193, 92, 28]", - "total_badness": 5992.5764939 + "ne3d": 3267, + "quality_histogram": "[3, 15, 32, 52, 50, 38, 44, 76, 118, 161, 234, 258, 360, 375, 419, 411, 310, 195, 94, 22]", + "total_badness": 6011.5192864 }, { "angles_tet": [ - 1.2156, + 1.2134, 169.94 ], "angles_trig": [ - 3.0435, + 2.0839, 165.56 ], "ne1d": 956, "ne2d": 2828, - "ne3d": 8549, - "quality_histogram": "[3, 9, 39, 50, 44, 51, 59, 59, 82, 133, 195, 336, 560, 830, 1174, 1357, 1462, 1224, 706, 176]", - "total_badness": 12575.367761 + "ne3d": 8577, + "quality_histogram": "[3, 9, 37, 48, 48, 52, 58, 60, 87, 127, 205, 328, 507, 805, 1199, 1394, 1476, 1215, 736, 183]", + "total_badness": 12579.939101 }, { "angles_tet": [ - 1.1519, - 168.31 + 1.3345, + 171.17 ], "angles_trig": [ - 3.4032, - 150.86 + 1.7811, + 158.38 ], "ne1d": 1554, "ne2d": 6372, - "ne3d": 31639, - "quality_histogram": "[2, 8, 13, 8, 24, 53, 51, 73, 92, 189, 305, 634, 1290, 2378, 3824, 5340, 6177, 5876, 4146, 1156]", - "total_badness": 40882.230035 + "ne3d": 31588, + "quality_histogram": "[2, 7, 14, 6, 25, 55, 52, 67, 91, 190, 307, 635, 1249, 2307, 3892, 5308, 6146, 5974, 4098, 1163]", + "total_badness": 40793.027008 }, { "angles_tet": [ @@ -2191,9 +2191,9 @@ ], "ne1d": 2992, "ne2d": 23322, - "ne3d": 281660, - "quality_histogram": "[4, 9, 10, 11, 11, 22, 32, 66, 101, 250, 741, 2131, 5596, 13622, 27762, 44429, 59897, 63856, 48363, 14747]", - "total_badness": 344296.42526 + "ne3d": 281957, + "quality_histogram": "[4, 9, 10, 11, 11, 21, 33, 65, 96, 260, 755, 2146, 5563, 13605, 27734, 44577, 59933, 63963, 48268, 14893]", + "total_badness": 344644.09939 } ], "revolution.geo": [ @@ -2214,33 +2214,33 @@ }, { "angles_tet": [ - 12.622, - 146.3 + 8.7903, + 155.06 ], "angles_trig": [ - 15.111, - 130.65 + 15.518, + 131.14 ], "ne1d": 160, "ne2d": 822, - "ne3d": 1231, - "quality_histogram": "[0, 0, 0, 0, 0, 11, 51, 85, 105, 139, 138, 152, 155, 101, 76, 79, 66, 43, 24, 6]", - "total_badness": 2255.1850071 + "ne3d": 1234, + "quality_histogram": "[0, 0, 0, 1, 0, 10, 62, 86, 121, 132, 145, 139, 147, 99, 95, 67, 61, 38, 23, 8]", + "total_badness": 2290.4515055 }, { "angles_tet": [ - 15.408, + 16.884, 145.04 ], "angles_trig": [ - 14.362, - 134.93 + 16.408, + 134.95 ], "ne1d": 240, "ne2d": 1830, - "ne3d": 3864, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 3, 31, 69, 157, 283, 417, 507, 494, 513, 422, 403, 319, 206, 40]", - "total_badness": 5758.3866216 + "ne3d": 3859, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 6, 25, 68, 162, 284, 407, 508, 515, 505, 411, 383, 323, 208, 54]", + "total_badness": 5750.8446823 }, { "angles_tet": [ @@ -2291,18 +2291,18 @@ "screw.step": [ { "angles_tet": [ - 15.138, - 148.37 + 15.139, + 148.36 ], "angles_trig": [ - 17.355, + 17.363, 140.59 ], "ne1d": 400, "ne2d": 1436, - "ne3d": 2341, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 15, 60, 96, 166, 202, 251, 312, 271, 259, 270, 191, 140, 90, 18]", - "total_badness": 3714.0468775 + "ne3d": 2342, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 16, 61, 92, 165, 209, 246, 307, 280, 262, 272, 182, 148, 84, 18]", + "total_badness": 3718.1755695 }, { "angles_tet": [ @@ -2322,17 +2322,17 @@ { "angles_tet": [ 20.515, - 144.02 + 144.03 ], "angles_trig": [ - 20.575, - 124.46 + 24.891, + 120.48 ], "ne1d": 666, "ne2d": 4922, - "ne3d": 31526, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 2, 6, 35, 90, 306, 711, 1685, 3214, 4996, 6794, 6910, 5193, 1584]", - "total_badness": 38669.670326 + "ne3d": 31540, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 1, 5, 31, 92, 290, 707, 1762, 3221, 4997, 6712, 6966, 5146, 1610]", + "total_badness": 38689.280913 } ], "sculpture.geo": [ @@ -2430,63 +2430,63 @@ "shaft.geo": [ { "angles_tet": [ - 8.741, - 169.01 + 9.1003, + 164.73 ], "angles_trig": [ - 9.2536, - 148.93 + 9.2165, + 146.85 ], "ne1d": 708, "ne2d": 1722, - "ne3d": 2780, - "quality_histogram": "[0, 0, 1, 10, 28, 29, 48, 46, 95, 147, 260, 397, 330, 277, 253, 288, 248, 181, 109, 33]", - "total_badness": 4601.9915591 + "ne3d": 2725, + "quality_histogram": "[0, 0, 3, 6, 15, 19, 28, 47, 87, 138, 286, 386, 316, 291, 250, 298, 242, 178, 104, 31]", + "total_badness": 4420.5345142 }, { "angles_tet": [ - 14.566, - 156.38 + 15.158, + 158.0 ], "angles_trig": [ 17.101, - 120.3 + 134.17 ], "ne1d": 410, "ne2d": 606, - "ne3d": 870, - "quality_histogram": "[0, 0, 0, 0, 0, 3, 2, 5, 22, 36, 42, 53, 91, 101, 127, 131, 94, 85, 47, 31]", - "total_badness": 1263.6238885 + "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 }, { "angles_tet": [ - 9.5449, - 167.3 + 7.5703, + 165.31 ], "angles_trig": [ - 10.216, - 148.27 + 12.063, + 152.34 ], "ne1d": 510, "ne2d": 1004, - "ne3d": 2013, - "quality_histogram": "[0, 0, 2, 11, 38, 79, 90, 131, 106, 114, 113, 172, 155, 218, 217, 207, 190, 98, 58, 14]", - "total_badness": 3713.7502435 + "ne3d": 1832, + "quality_histogram": "[0, 0, 2, 8, 9, 35, 44, 79, 84, 110, 107, 164, 159, 194, 235, 212, 202, 104, 66, 18]", + "total_badness": 3083.8429043 }, { "angles_tet": [ - 11.328, + 14.303, 162.65 ], "angles_trig": [ - 13.746, - 135.37 + 14.459, + 150.06 ], "ne1d": 708, "ne2d": 1722, - "ne3d": 2720, - "quality_histogram": "[0, 0, 0, 1, 3, 2, 11, 23, 52, 119, 264, 396, 344, 289, 274, 315, 272, 207, 111, 37]", - "total_badness": 4172.9994061 + "ne3d": 2703, + "quality_histogram": "[0, 0, 0, 0, 2, 3, 11, 17, 48, 118, 246, 396, 350, 292, 274, 307, 281, 221, 102, 35]", + "total_badness": 4122.3827179 }, { "angles_tet": [ @@ -2505,18 +2505,18 @@ }, { "angles_tet": [ - 25.341, - 142.09 + 22.61, + 139.73 ], "angles_trig": [ - 22.461, - 120.2 + 22.297, + 118.87 ], "ne1d": 1792, "ne2d": 10600, - "ne3d": 63811, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 2, 22, 127, 439, 1283, 3078, 6205, 10007, 13534, 14326, 11042, 3746]", - "total_badness": 77678.178377 + "ne3d": 63839, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 4, 22, 130, 424, 1292, 3122, 6208, 9992, 13576, 14305, 11041, 3723]", + "total_badness": 77729.577133 } ], "sphere.geo": [ @@ -2997,18 +2997,18 @@ }, { "angles_tet": [ - 1.8454, - 174.07 + 1.7223, + 174.81 ], "angles_trig": [ - 3.7635, - 166.86 + 4.9314, + 166.92 ], "ne1d": 0, "ne2d": 692, - "ne3d": 3289, - "quality_histogram": "[22, 357, 521, 490, 397, 337, 276, 212, 158, 125, 86, 85, 59, 35, 37, 25, 30, 23, 11, 3]", - "total_badness": 17806.714921 + "ne3d": 2691, + "quality_histogram": "[26, 258, 398, 331, 349, 264, 205, 192, 123, 145, 87, 67, 74, 48, 30, 33, 29, 20, 11, 1]", + "total_badness": 14056.890733 }, { "angles_tet": [ @@ -3021,9 +3021,9 @@ ], "ne1d": 0, "ne2d": 1446, - "ne3d": 2732, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 2, 1, 14, 50, 134, 229, 351, 416, 425, 383, 313, 197, 166, 51]", - "total_badness": 3892.9500522 + "ne3d": 2739, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 2, 2, 15, 48, 132, 221, 357, 421, 424, 382, 318, 204, 161, 52]", + "total_badness": 3899.5318975 }, { "angles_tet": [ @@ -3365,33 +3365,33 @@ }, { "angles_tet": [ - 18.404, - 153.38 + 19.944, + 152.59 ], "angles_trig": [ - 26.007, - 121.51 + 25.599, + 123.4 ], "ne1d": 68, "ne2d": 100, - "ne3d": 150, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 2, 2, 4, 6, 12, 12, 8, 13, 24, 18, 18, 23, 4, 4]", - "total_badness": 222.6797729 + "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 }, { "angles_tet": [ - 12.34, - 161.32 + 12.268, + 164.21 ], "angles_trig": [ - 12.084, - 152.05 + 15.1, + 144.2 ], "ne1d": 102, "ne2d": 238, - "ne3d": 497, - "quality_histogram": "[0, 0, 0, 2, 11, 31, 40, 56, 65, 43, 34, 21, 26, 25, 30, 31, 43, 28, 8, 3]", - "total_badness": 1042.5778658 + "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 }, { "angles_tet": [ @@ -3410,18 +3410,18 @@ }, { "angles_tet": [ - 19.806, - 141.75 + 21.286, + 140.31 ], "angles_trig": [ - 22.382, - 115.67 + 22.446, + 114.89 ], "ne1d": 214, "ne2d": 910, - "ne3d": 1906, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 1, 2, 14, 28, 73, 129, 185, 278, 363, 378, 262, 155, 38]", - "total_badness": 2512.811709 + "ne3d": 1889, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 1, 2, 13, 31, 69, 126, 193, 280, 351, 341, 277, 168, 37]", + "total_badness": 2489.1406753 }, { "angles_tet": [ From b37a3e6cf62bc34e82ae2f985d9b70fefd63b6b3 Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Fri, 17 Jul 2020 18:00:38 +0200 Subject: [PATCH 067/384] comment code for non orthogonal boundarylayers (not working if multiple surfaces come together) --- libsrc/meshing/boundarylayer.cpp | 36 ++++++++++++++++---------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/libsrc/meshing/boundarylayer.cpp b/libsrc/meshing/boundarylayer.cpp index 953a96c7..710251a6 100644 --- a/libsrc/meshing/boundarylayer.cpp +++ b/libsrc/meshing/boundarylayer.cpp @@ -238,24 +238,24 @@ namespace netgen } // project growthvector on surface for inner angles - for(const auto& sel : mesh.SurfaceElements()) - if(!blp.surfid.Contains(sel.GetIndex())) - { - auto n = GetSurfaceNormal(mesh, sel); - for(auto pi : sel.PNums()) - { - if(growthvectors[pi].Length2() == 0.) - continue; - auto& g = growthvectors[pi]; - auto ng = n * g; - auto gg = g * g; - auto nn = n * n; - if(fabs(ng*ng-nn*gg) < 1e-12 || fabs(ng) < 1e-12) continue; - auto a = -ng*ng/(ng*ng-nn * gg); - auto b = ng*gg/(ng*ng-nn*gg); - g += a*g + b*n; - } - } + // for(const auto& sel : mesh.SurfaceElements()) + // if(!blp.surfid.Contains(sel.GetIndex())) + // { + // auto n = GetSurfaceNormal(mesh, sel); + // for(auto pi : sel.PNums()) + // { + // if(growthvectors[pi].Length2() == 0.) + // continue; + // auto& g = growthvectors[pi]; + // auto ng = n * g; + // auto gg = g * g; + // auto nn = n * n; + // if(fabs(ng*ng-nn*gg) < 1e-12 || fabs(ng) < 1e-12) continue; + // auto a = -ng*ng/(ng*ng-nn * gg); + // auto b = ng*gg/(ng*ng-nn*gg); + // g += a*g + b*n; + // } + // } if (!blp.grow_edges) { From a0a189869e1748a663e6b26063d790c2346cef26 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Fri, 17 Jul 2020 18:16:54 +0200 Subject: [PATCH 068/384] SplitImprove2 optimization path --- libsrc/meshing/improve3.cpp | 219 +++++++++++++++++++++++++++++++++++ libsrc/meshing/improve3.hpp | 1 + libsrc/meshing/meshclass.cpp | 2 + libsrc/meshing/meshfunc.cpp | 2 +- 4 files changed, 223 insertions(+), 1 deletion(-) diff --git a/libsrc/meshing/improve3.cpp b/libsrc/meshing/improve3.cpp index 78ef49f9..07b27110 100644 --- a/libsrc/meshing/improve3.cpp +++ b/libsrc/meshing/improve3.cpp @@ -3902,6 +3902,225 @@ void MeshOptimize3d :: SwapImprove2 (Mesh & mesh, OPTIMIZEGOAL goal) (*testout) << "swapimprove2 done" << "\n"; } +// Split two opposite edges of very flat tet and let all 4 new segments have one common vertex +// Imagine a square with 2 diagonals -> new point where diagonals cross, remove the flat tet +void MeshOptimize3d :: SplitImprove2 (Mesh & mesh, OPTIMIZEGOAL goal) +{ + double bad1 = mesh.CalcTotalBad (mp); + cout << "Total badness before splitimprove2= " << bad1 << endl; +// cout << "SplitImprove2" << endl; + int ne = mesh.GetNE(); + auto elements_of_point = mesh.CreatePoint2ElementTable(); + + Array el_badness (ne); + + ParallelForRange(Range(ne), [&] (auto myrange) + { + for (ElementIndex ei : myrange) + { + if(mp.only3D_domain_nr && mp.only3D_domain_nr != mesh[ei].GetIndex()) + continue; + el_badness[ei] = CalcBad (mesh.Points(), mesh[ei], 0); + } + }); + + mesh.BoundaryEdge (1,2); // ensure the boundary-elements table is built + +// cout << "badness : " << endl << el_badness << endl; + + // TODO: Parallelization + for (ElementIndex ei : Range(ne) ) + { + auto & el = mesh[ei]; + if(el.GetNP() != 4) + continue; + + // Optimize only bad elements +// if(el_badness[ei] < 10000) +// continue; + +// cout << "element " << ei << '\t' << '\t' << el[0] << ',' << el[1] << ',' << el[2] << ',' << el[3] << endl; + + // search for very flat tets, with two disjoint edges nearly crossing, like a rectangle with diagonals + static constexpr int tetedges[6][2] = + { { 0, 1 }, { 0, 2 }, { 0, 3 }, + { 1, 2 }, { 1, 3 }, { 2, 3 } }; + + int minedge = -1; + double mindist = 1e99; + + for (int i : Range(3)) + { + auto pi0 = el[tetedges[i][0]]; + auto pi1 = el[tetedges[i][1]]; + auto pi2 = el[tetedges[5-i][0]]; + auto pi3 = el[tetedges[5-i][1]]; + +// +// Point3d p0 = mesh[pi0]; +// Point3d p1 = mesh[pi1]; +// Point3d p2 = mesh[pi2]; +// Point3d p3 = mesh[pi3]; + + double dist = MinDistLL2(mesh[pi0], mesh[pi1], mesh[pi2], mesh[pi3]); + if(dist has_one_point0; + ArrayMem has_one_point1; + ArrayMem has_both_points0; + ArrayMem has_both_points1; + + Point3d p[4] = { mesh[el[0]], mesh[el[1]], mesh[el[2]], mesh[el[3]] }; + auto center = Center(p[0], p[1], p[2], p[3]); + PointIndex pinew = mesh.AddPoint (center); + MeshPoint pnew = mesh[pinew]; +// cout << "check el " << ei << endl; + + bool valid = true; + // find all tets with edge (pi0,pi1) or (pi2,pi3) + for (auto ei0 : elements_of_point[pi0] ) + { + Element & elem = mesh[ei0]; + if (elem.IsDeleted()) valid = false; + if (ei0 == ei) continue; + if(mesh[ei0].GetNP()!=4) + valid = false; + + if (elem[0] == pi1 || elem[1] == pi1 || elem[2] == pi1 || elem[3] == pi1) + { + if(!has_both_points0.Contains(ei0)) + has_both_points0.Append (ei0); + } + else + { + if(!has_one_point0.Contains(ei0)) + has_one_point0.Append (ei0); + } + } + for (auto ei1 : elements_of_point[pi2] ) + { +// cout << ei1 << ','; + Element & elem = mesh[ei1]; + if (elem.IsDeleted()) valid = false; + if (ei1 == ei) continue; + if(mesh[ei1].GetNP()!=4) + valid = false; + + if (elem[0] == pi3 || elem[1] == pi3 || elem[2] == pi3 || elem[3] == pi3) + { + if(mesh[ei1].GetNP()!=4) + valid = false; + if(!has_both_points1.Contains(ei1)) + has_both_points1.Append (ei1); + } + else + { + if(!has_one_point1.Contains(ei1)) + has_one_point1.Append (ei1); + } + } + if(!valid) continue; +// cout << endl; +// +// cout << "both0 " << endl << has_both_points0 << endl; +// cout << "both1 " << endl << has_both_points0 << endl; + double badness_before = el_badness[ei]; + + double badness_after = 0.0; + PointIndex dummy{-1}; + for (auto ei0 : has_both_points0) + { + badness_before += el_badness[ei0]; + badness_after += CalcBadReplacePoints (mesh.Points(), mp, mesh[ei0], 0, pi1, dummy, pnew); + badness_after += CalcBadReplacePoints (mesh.Points(), mp, mesh[ei0], 0, pi0, dummy, pnew); + } + for (auto ei1 : has_both_points1) + { + badness_before += el_badness[ei1]; + badness_after += CalcBadReplacePoints (mesh.Points(), mp, mesh[ei1], 0, pi3, dummy, pnew); + badness_after += CalcBadReplacePoints (mesh.Points(), mp, mesh[ei1], 0, pi2, dummy, pnew); + } + if(badness_after Date: Mon, 20 Jul 2020 18:56:36 +0200 Subject: [PATCH 070/384] SplitImprove2 - cleanup, new point at min dist of edges --- libsrc/gprim/geomtest3d.cpp | 64 +++++++++++++++++++++++++++++++----- libsrc/gprim/geomtest3d.hpp | 3 ++ libsrc/meshing/improve3.cpp | 27 ++++----------- libsrc/meshing/improve3.hpp | 8 +++++ libsrc/meshing/meshclass.cpp | 2 -- 5 files changed, 73 insertions(+), 31 deletions(-) diff --git a/libsrc/gprim/geomtest3d.cpp b/libsrc/gprim/geomtest3d.cpp index 0c117a10..5c3a827a 100644 --- a/libsrc/gprim/geomtest3d.cpp +++ b/libsrc/gprim/geomtest3d.cpp @@ -1035,6 +1035,39 @@ double MinDistLP2 (const Point3d & lp1, const Point3d & lp2, const Point3d & p) } +double MinDistLP2 (const Point3d & lp1, const Point3d & lp2, const Point3d & p, double & lam) +{ + Vec3d v(lp1, lp2); + Vec3d vlp(lp1, p); + + // dist(lam) = \| vlp \|^2 - 2 lam (v1p, v) + lam^2 \| v \|^2 + + // lam = (v * vlp) / (v * v); + // if (lam < 0) lam = 0; + // if (lam > 1) lam = 1; + + double num = v*vlp; + double den = v*v; + + if (num <= 0) + { + lam = 0.0; + return Dist2 (lp1, p); + } + + if (num >= den) + { + lam = 1.0; + return Dist2 (lp2, p); + } + + lam = num/den; + if (den > 0) + return vlp.Length2() - num * num /den; + else + return vlp.Length2(); +} + double MinDistTP2 (const Point3d & tp1, const Point3d & tp2, const Point3d & tp3, const Point3d & p) @@ -1102,7 +1135,7 @@ double MinDistTP2 (const Point3d & tp1, const Point3d & tp2, // 0 checks !!! double MinDistLL2 (const Point3d & l1p1, const Point3d & l1p2, - const Point3d & l2p1, const Point3d & l2p2) + const Point3d & l2p1, const Point3d & l2p2, double & lam1, double & lam2 ) { // dist(lam1,lam2) = \| l2p1+lam2v2 - (l1p1+lam1 v1) \| // min ! @@ -1112,7 +1145,7 @@ double MinDistLL2 (const Point3d & l1p1, const Point3d & l1p2, Vec3d v2 (l2p1, l2p2); double a11, a12, a22, rs1, rs2; - double lam1, lam2, det; + double det; a11 = v1*v1; a12 = -(v1*v2); @@ -1138,14 +1171,27 @@ double MinDistLL2 (const Point3d & l1p1, const Point3d & l1p2, } double minv, hv; - minv = MinDistLP2 (l1p1, l1p2, l2p1); - hv = MinDistLP2 (l1p1, l1p2, l2p2); - if (hv < minv) minv = hv; + minv = MinDistLP2 (l1p1, l1p2, l2p1, lam1); + lam2 = 0.; + hv = MinDistLP2 (l1p1, l1p2, l2p2, lam1); + if (hv < minv) + { + lam2 = 1.; + minv = hv; + } - hv = MinDistLP2 (l2p1, l2p2, l1p1); - if (hv < minv) minv = hv; - hv = MinDistLP2 (l2p1, l2p2, l1p2); - if (hv < minv) minv = hv; + hv = MinDistLP2 (l2p1, l2p2, l1p1, lam2); + if (hv < minv) + { + lam1 = 0.; + minv = hv; + } + hv = MinDistLP2 (l2p1, l2p2, l1p2, lam2); + if (hv < minv) + { + lam1 = 1.; + minv = hv; + } return minv; } diff --git a/libsrc/gprim/geomtest3d.hpp b/libsrc/gprim/geomtest3d.hpp index a8bb0266..c1fb1186 100644 --- a/libsrc/gprim/geomtest3d.hpp +++ b/libsrc/gprim/geomtest3d.hpp @@ -91,6 +91,9 @@ extern double MinDistTP2 (const Point3d & tp1, const Point3d & tp2, extern double MinDistLL2 (const Point3d & l1p1, const Point3d & l1p2, const Point3d & l2p1, const Point3d & l2p2); +extern double MinDistLL2 (const Point3d & l1p1, const Point3d & l1p2, + const Point3d & l2p1, const Point3d & l2p2, double & lam1, double & lam2 ); + } #endif diff --git a/libsrc/meshing/improve3.cpp b/libsrc/meshing/improve3.cpp index 33af9de3..e08e9b7a 100644 --- a/libsrc/meshing/improve3.cpp +++ b/libsrc/meshing/improve3.cpp @@ -3920,12 +3920,7 @@ void MeshOptimize3d :: SplitImprove2 (Mesh & mesh, OPTIMIZEGOAL goal) { if(mp.only3D_domain_nr && mp.only3D_domain_nr != mesh[ei].GetIndex()) continue; -// el_badness[ei] = CalcBad (mesh.Points(), mesh[ei], 0); - const auto & el = mesh[ei]; - if(el.GetNP()==4) - el_badness[ei] = CalcTetBadness (mesh[el[0]], mesh[el[1]], mesh[el[2]], mesh[el[3]], 0, mp); - else - el_badness[ei] = 0.0; + el_badness[ei] = CalcBad (mesh.Points(), mesh[ei], 0); } }); @@ -3953,6 +3948,7 @@ void MeshOptimize3d :: SplitImprove2 (Mesh & mesh, OPTIMIZEGOAL goal) int minedge = -1; double mindist = 1e99; + double minlam0, minlam1; for (int i : Range(3)) { @@ -3967,11 +3963,14 @@ void MeshOptimize3d :: SplitImprove2 (Mesh & mesh, OPTIMIZEGOAL goal) // Point3d p2 = mesh[pi2]; // Point3d p3 = mesh[pi3]; - double dist = MinDistLL2(mesh[pi0], mesh[pi1], mesh[pi2], mesh[pi3]); + double lam0, lam1; + double dist = MinDistLL2(mesh[pi0], mesh[pi1], mesh[pi2], mesh[pi3], lam0, lam1 ); if(dist has_both_points1; Point3d p[4] = { mesh[el[0]], mesh[el[1]], mesh[el[2]], mesh[el[3]] }; - auto center = Center(p[0], p[1], p[2], p[3]); + auto center = Center(p[0]+minlam0*(p[1]-p[0]), p[2]+minlam1*(p[3]-p[2])); MeshPoint pnew; pnew(0) = center.X(); @@ -4074,13 +4073,8 @@ void MeshOptimize3d :: SplitImprove2 (Mesh & mesh, OPTIMIZEGOAL goal) if(newel1[i] == pi0) newel1[i] = pinew; if(newel2[i] == pi1) newel2[i] = pinew; } - if (!mesh.LegalTet (newel1)) cout << "newel1 illegal tet" << endl; mesh.AddVolumeElement (newel1); - if (!mesh.LegalTet (newel2)) cout << "newel2 illegal tet" << endl; mesh.AddVolumeElement (newel2); -// cout << "del element " << ei1 << ':' << oldel[0] << ',' << oldel[1] << ',' << oldel[2] << ',' << oldel[3] << endl; -// cout << "add element " << newel1[0] << ',' << newel1[1] << ',' << newel1[2] << ',' << newel1[3] << endl; -// cout << "add element " << newel2[0] << ',' << newel2[1] << ',' << newel2[2] << ',' << newel2[3] << endl; } for (auto ei1 : has_both_points1) { @@ -4096,18 +4090,11 @@ void MeshOptimize3d :: SplitImprove2 (Mesh & mesh, OPTIMIZEGOAL goal) if(newel1[i] == pi2) newel1[i] = pinew; if(newel2[i] == pi3) newel2[i] = pinew; } -// cout << "del element " << ei1 << ':' << oldel[0] << ',' << oldel[1] << ',' << oldel[2] << ',' << oldel[3] << endl; -// cout << "add element " << newel1[0] << ',' << newel1[1] << ',' << newel1[2] << ',' << newel1[3] << endl; -// cout << "add element " << newel2[0] << ',' << newel2[1] << ',' << newel2[2] << ',' << newel2[3] << endl; - if (!mesh.LegalTet (newel1)) cout << "newel1 illegal tet" << endl; mesh.AddVolumeElement (newel1); - if (!mesh.LegalTet (newel2)) cout << "newel2 illegal tet" << endl; mesh.AddVolumeElement (newel2); } } } - MeshTopology mt(mesh); - mt.Update(); mesh.Compress(); bad1 = mesh.CalcTotalBad (mp); cout << "Total badness after splitimprove2= " << bad1 << endl; diff --git a/libsrc/meshing/improve3.hpp b/libsrc/meshing/improve3.hpp index 9da6f548..25de63f3 100644 --- a/libsrc/meshing/improve3.hpp +++ b/libsrc/meshing/improve3.hpp @@ -50,6 +50,14 @@ public: return 0; } + double + CalcBadPow (const Mesh::T_POINTS & points, const Element & elem, double h) + { + if (elem.GetType() == TET) + return pow (max2(CalcTetBadness (points[elem[0]], points[elem[1]], + points[elem[2]], points[elem[3]], h, mp), 1e-10) , 1.0/mp.opterrpow); + return 0; + } double CalcTotalBad (const Mesh::T_POINTS & points, const Array & elements) diff --git a/libsrc/meshing/meshclass.cpp b/libsrc/meshing/meshclass.cpp index 0efbc756..76a22ffc 100644 --- a/libsrc/meshing/meshclass.cpp +++ b/libsrc/meshing/meshclass.cpp @@ -3620,8 +3620,6 @@ namespace netgen // FindOpenElements(); timestamp = NextTimeStamp(); lock.UnLock(); - FindOpenElements(); - CheckVolumeMesh (); } void Mesh :: OrderElements() From ba5e741ad32b27060c3f27db5c61088043f831b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20Sch=C3=B6berl?= Date: Wed, 22 Jul 2020 10:15:15 +0200 Subject: [PATCH 071/384] adding pybind11/stl to ngcore (needed for BitArray ctor) --- libsrc/core/python_ngcore.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libsrc/core/python_ngcore.hpp b/libsrc/core/python_ngcore.hpp index 92cbbe62..a8ef5755 100644 --- a/libsrc/core/python_ngcore.hpp +++ b/libsrc/core/python_ngcore.hpp @@ -5,6 +5,7 @@ #include #include #include +#include #include "array.hpp" #include "archive.hpp" From e17de17385ad656e41b41797ca98a153273f69b2 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Thu, 23 Jul 2020 12:24:43 +0200 Subject: [PATCH 072/384] SplitImprove2 - further cleanup, handle Pyramids --- libsrc/meshing/improve3.cpp | 168 ++++++++++++++++++++---------------- libsrc/meshing/improve3.hpp | 37 +++----- libsrc/meshing/meshfunc.cpp | 3 +- 3 files changed, 111 insertions(+), 97 deletions(-) diff --git a/libsrc/meshing/improve3.cpp b/libsrc/meshing/improve3.cpp index e08e9b7a..5b4416bc 100644 --- a/libsrc/meshing/improve3.cpp +++ b/libsrc/meshing/improve3.cpp @@ -16,18 +16,85 @@ namespace netgen // Calc badness of new element where pi1 and pi2 are replaced by pnew -double CalcBadReplacePoints (const Mesh::T_POINTS & points, const MeshingParameters & mp, const Element & elem, double h, PointIndex &pi1, PointIndex &pi2, MeshPoint &pnew) +static double CalcBadReplacePoints (const Mesh::T_POINTS & points, const MeshingParameters & mp, const Element & elem, double h, PointIndex &pi1, PointIndex &pi2, MeshPoint &pnew) { - if (elem.GetType() != TET) return 0; + if (elem.GetType() != TET && elem.GetType() != PYRAMID) + return 0; - MeshPoint* p[] = {&points[elem[0]], &points[elem[1]], &points[elem[2]], &points[elem[3]]}; + MeshPoint p[5]; - for (auto i : Range(4)) - if(elem[i]==pi1 || elem[i]==pi2) p[i] = &pnew; + for (auto i : Range(elem.GetNP())) + { + auto pi = elem[i]; + if(pi==pi1 || pi==pi2) + p[i] = pnew; + else + p[i] = points[pi]; + } - return CalcTetBadness (*p[0], *p[1], *p[2], *p[3], h, mp); + if (elem.GetType() == TET) + return CalcTetBadness (p[0], p[1], p[2], p[3], h, mp); + if (elem.GetType() == PYRAMID) + return CalcTetBadness (p[0], p[1], p[2], p[4], h, mp) + + CalcTetBadness (p[2], p[3], p[0], p[4], h, mp); + return 0; } +static ArrayMem SplitElement (Element old, PointIndex pi0, PointIndex pi1, PointIndex pinew) +{ + ArrayMem new_elements; + // split element by cutting edge pi0,pi1 at pinew + auto np = old.GetNP(); + old.flags.illegal_valid = 0; + if(np == 4) + { + // Split tet into two tets + Element newel0 = old; + Element newel1 = old; + for (int i : Range(4)) + { + if(newel0[i] == pi0) newel0[i] = pinew; + if(newel1[i] == pi1) newel1[i] = pinew; + } + new_elements.Append(newel0); + new_elements.Append(newel1); + } + else if (np == 5) + { + // split pyramid into pyramid and two tets + Element new_pyramid = old; + new_pyramid[4] = pinew; + new_elements.Append(new_pyramid); + + auto pibase = (pi0==old[4]) ? pi1 : pi0; + auto pitop = (pi0==old[4]) ? pi0 : pi1; + + Element new_tet0 = old; + Element new_tet1 = old; + new_tet0.SetType(TET); + new_tet1.SetType(TET); + + size_t pibase_index=0; + for(auto i : Range(4)) + if(old[i]==pibase) + pibase_index = i; + + new_tet0[0] = old[(pibase_index+1)%4]; + new_tet0[1] = old[(pibase_index+2)%4]; + new_tet0[2] = pinew; + new_tet0[3] = pitop; + new_elements.Append(new_tet0); + + new_tet1[0] = old[(pibase_index+2)%4]; + new_tet1[1] = old[(pibase_index+3)%4]; + new_tet1[2] = pinew; + new_tet1[3] = pitop; + new_elements.Append(new_tet1); + } + + return new_elements; +}; + /* Combine two points to one. Set new point into the center, if both are @@ -59,6 +126,7 @@ double MeshOptimize3d :: CombineImproveEdge (Mesh & mesh, { Element & elem = mesh[ei]; if (elem.IsDeleted()) return false; + if(elem.GetType() != TET) return false; // TODO: implement case where pi0 or pi1 is top of a pyramid if (elem[0] == pi1 || elem[1] == pi1 || elem[2] == pi1 || elem[3] == pi1) { @@ -3907,8 +3975,6 @@ void MeshOptimize3d :: SwapImprove2 (Mesh & mesh, OPTIMIZEGOAL goal) void MeshOptimize3d :: SplitImprove2 (Mesh & mesh, OPTIMIZEGOAL goal) { double bad1 = mesh.CalcTotalBad (mp); - cout << "Total badness before splitimprove2= " << bad1 << endl; -// cout << "SplitImprove2" << endl; int ne = mesh.GetNE(); auto elements_of_point = mesh.CreatePoint2ElementTable(); @@ -3926,21 +3992,17 @@ void MeshOptimize3d :: SplitImprove2 (Mesh & mesh, OPTIMIZEGOAL goal) mesh.BoundaryEdge (1,2); // ensure the boundary-elements table is built -// cout << "badness : " << endl << el_badness << endl; - // TODO: Parallelization for (ElementIndex ei : Range(ne) ) { auto & el = mesh[ei]; - if(el.GetNP() != 4) + if(el.GetType() != TET) continue; // Optimize only bad elements -// if(el_badness[ei] < 10000) +// if(el_badness[ei] < 100) // continue; -// cout << "element " << ei << '\t' << '\t' << el[0] << ',' << el[1] << ',' << el[2] << ',' << el[3] << endl; - // search for very flat tets, with two disjoint edges nearly crossing, like a rectangle with diagonals static constexpr int tetedges[6][2] = { { 0, 1 }, { 0, 2 }, { 0, 3 }, @@ -3957,12 +4019,6 @@ void MeshOptimize3d :: SplitImprove2 (Mesh & mesh, OPTIMIZEGOAL goal) auto pi2 = el[tetedges[5-i][0]]; auto pi3 = el[tetedges[5-i][1]]; -// -// Point3d p0 = mesh[pi0]; -// Point3d p1 = mesh[pi1]; -// Point3d p2 = mesh[pi2]; -// Point3d p3 = mesh[pi3]; - double lam0, lam1; double dist = MinDistLL2(mesh[pi0], mesh[pi1], mesh[pi2], mesh[pi3], lam0, lam1 ); if(dist has_both_points0; ArrayMem has_both_points1; @@ -4000,7 +4052,6 @@ void MeshOptimize3d :: SplitImprove2 (Mesh & mesh, OPTIMIZEGOAL goal) pnew(0) = center.X(); pnew(1) = center.Y(); pnew(2) = center.Z(); -// cout << "check el " << ei << endl; bool valid = true; // find all tets with edge (pi0,pi1) or (pi2,pi3) @@ -4009,95 +4060,66 @@ void MeshOptimize3d :: SplitImprove2 (Mesh & mesh, OPTIMIZEGOAL goal) Element & elem = mesh[ei0]; if (elem.IsDeleted()) valid = false; if (ei0 == ei) continue; - if(mesh[ei0].GetNP()!=4) - valid = false; - if (elem[0] == pi1 || elem[1] == pi1 || elem[2] == pi1 || elem[3] == pi1) + if (elem[0] == pi1 || elem[1] == pi1 || elem[2] == pi1 || elem[3] == pi1 || (elem.GetNP()==5 && elem[4]==pi1) ) if(!has_both_points0.Contains(ei0)) has_both_points0.Append (ei0); } for (auto ei1 : elements_of_point[pi2] ) { -// cout << ei1 << ','; Element & elem = mesh[ei1]; if (elem.IsDeleted()) valid = false; if (ei1 == ei) continue; - if(mesh[ei1].GetNP()!=4) - valid = false; - if (elem[0] == pi3 || elem[1] == pi3 || elem[2] == pi3 || elem[3] == pi3) + if (elem[0] == pi3 || elem[1] == pi3 || elem[2] == pi3 || elem[3] == pi3 || (elem.GetNP()==5 && elem[4]==pi3)) if(!has_both_points1.Contains(ei1)) has_both_points1.Append (ei1); } if(!valid) continue; -// cout << endl; -// -// cout << "both0 " << endl << has_both_points0 << endl; -// cout << "both1 " << endl << has_both_points0 << endl; double badness_before = el_badness[ei]; double badness_after = 0.0; PointIndex dummy{-1}; + + PointIndex pinew = mesh.AddPoint (center); for (auto ei0 : has_both_points0) { badness_before += el_badness[ei0]; - badness_after += CalcBadReplacePoints (mesh.Points(), mp, mesh[ei0], 0, pi1, dummy, pnew); - badness_after += CalcBadReplacePoints (mesh.Points(), mp, mesh[ei0], 0, pi0, dummy, pnew); + auto new_els = SplitElement(mesh[ei0], pi0, pi1, pinew); + for(const auto & el : new_els) + badness_after += CalcBad (mesh.Points(), el, 0); } for (auto ei1 : has_both_points1) { badness_before += el_badness[ei1]; - badness_after += CalcBadReplacePoints (mesh.Points(), mp, mesh[ei1], 0, pi3, dummy, pnew); - badness_after += CalcBadReplacePoints (mesh.Points(), mp, mesh[ei1], 0, pi2, dummy, pnew); + auto new_els = SplitElement(mesh[ei1], pi2, pi3, pinew); + for(const auto & el : new_els) + badness_after += CalcBad (mesh.Points(), el, 0); } if(badness_after (hp); @@ -391,6 +390,19 @@ namespace netgen vgrad += vgradi; } + if(el.GetType()==PYRAMID) + { + f += CalcTetBadnessGrad (points[el[0]], + points[el[1]], + points[el[2]], + points[el[4]], -1, 4, vgradi, mp); + vgrad += vgradi; + f += CalcTetBadnessGrad (points[el[2]], + points[el[3]], + points[el[0]], + points[el[4]], -1, 4, vgradi, mp); + vgrad += vgradi; + } } points[actpind] = Point<3> (hp); @@ -423,6 +435,20 @@ namespace netgen vgrad += vgradi; } + + if(el.GetType()==PYRAMID) + { + f += CalcTetBadnessGrad (points[el[0]], + points[el[1]], + points[el[2]], + points[el[4]], -1, 4, vgradi, mp); + vgrad += vgradi; + f += CalcTetBadnessGrad (points[el[2]], + points[el[3]], + points[el[0]], + points[el[4]], -1, 4, vgradi, mp); + vgrad += vgradi; + } } points[actpind] = Point<3> (hp); From 3fae0e029f30050fe0c8683a9f4ebddcea8a4c4c Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Thu, 23 Jul 2020 12:20:39 +0200 Subject: [PATCH 074/384] activate SplitImprove2 by default --- libsrc/meshing/meshtype.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libsrc/meshing/meshtype.hpp b/libsrc/meshing/meshtype.hpp index e6ccc83e..180b24f6 100644 --- a/libsrc/meshing/meshtype.hpp +++ b/libsrc/meshing/meshtype.hpp @@ -1217,12 +1217,13 @@ namespace netgen // s .. swap faces // c .. combine elements // d .. divide elements + // D .. divide and join opposite edges, remove element // p .. plot, no pause // P .. plot, Pause // h .. Histogramm, no pause // H .. Histogramm, pause */ - string optimize3d = "cmdmustm"; + string optimize3d = "cmdDmustm"; /// number of 3d optimization steps int optsteps3d = 3; /** From b689d13efeea0a8afd3b50ff8ac8033a1ebab9da Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Thu, 23 Jul 2020 13:18:14 +0200 Subject: [PATCH 075/384] SplitImprove2 - optimize only bad elements, update results --- libsrc/meshing/improve3.cpp | 4 +- tests/pytest/results.json | 484 +++++++++++++++--------------------- 2 files changed, 197 insertions(+), 291 deletions(-) diff --git a/libsrc/meshing/improve3.cpp b/libsrc/meshing/improve3.cpp index 5b4416bc..940bc2ed 100644 --- a/libsrc/meshing/improve3.cpp +++ b/libsrc/meshing/improve3.cpp @@ -4000,8 +4000,8 @@ void MeshOptimize3d :: SplitImprove2 (Mesh & mesh, OPTIMIZEGOAL goal) continue; // Optimize only bad elements -// if(el_badness[ei] < 100) -// continue; + if(el_badness[ei] < 100) + continue; // search for very flat tets, with two disjoint edges nearly crossing, like a rectangle with diagonals static constexpr int tetedges[6][2] = diff --git a/tests/pytest/results.json b/tests/pytest/results.json index 9b6540a7..6898733e 100644 --- a/tests/pytest/results.json +++ b/tests/pytest/results.json @@ -124,8 +124,8 @@ }, { "angles_tet": [ - 16.335, - 152.61 + 15.88, + 154.64 ], "angles_trig": [ 20.0, @@ -133,9 +133,9 @@ ], "ne1d": 136, "ne2d": 222, - "ne3d": 348, - "quality_histogram": "[0, 0, 0, 0, 0, 4, 3, 5, 4, 9, 18, 23, 27, 46, 55, 62, 55, 20, 16, 1]", - "total_badness": 514.05343802 + "ne3d": 352, + "quality_histogram": "[0, 0, 0, 0, 0, 5, 5, 7, 4, 7, 14, 26, 24, 54, 64, 61, 47, 18, 14, 2]", + "total_badness": 527.329265 }, { "angles_tet": [ @@ -293,33 +293,33 @@ }, { "angles_tet": [ - 13.26, - 163.45 + 14.466, + 161.38 ], "angles_trig": [ - 11.907, - 152.58 + 13.564, + 150.65 ], "ne1d": 32, "ne2d": 220, - "ne3d": 556, - "quality_histogram": "[0, 0, 0, 4, 7, 14, 27, 33, 41, 29, 37, 47, 34, 50, 41, 51, 63, 38, 30, 10]", - "total_badness": 997.95710204 + "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 }, { "angles_tet": [ - 2.8811, - 172.75 + 5.6575, + 169.44 ], "angles_trig": [ - 9.0948, - 156.22 + 7.092, + 155.41 ], "ne1d": 48, "ne2d": 428, - "ne3d": 770, - "quality_histogram": "[2, 11, 24, 35, 27, 40, 36, 49, 76, 95, 61, 81, 68, 31, 52, 32, 17, 19, 12, 2]", - "total_badness": 2061.8554811 + "ne3d": 763, + "quality_histogram": "[0, 1, 12, 30, 35, 44, 39, 49, 82, 100, 68, 81, 55, 44, 49, 23, 22, 19, 8, 2]", + "total_badness": 1832.2349397 }, { "angles_tet": [ @@ -471,9 +471,9 @@ ], "ne1d": 262, "ne2d": 726, - "ne3d": 2153, - "quality_histogram": "[0, 5, 20, 35, 79, 117, 112, 108, 75, 47, 53, 85, 111, 177, 250, 290, 240, 204, 118, 27]", - "total_badness": 4183.5255584 + "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.9281305 }, { "angles_tet": [ @@ -507,18 +507,18 @@ }, { "angles_tet": [ - 5.4026, - 168.34 + 5.9887, + 161.33 ], "angles_trig": [ - 13.552, + 13.133, 150.46 ], "ne1d": 262, "ne2d": 726, - "ne3d": 2048, - "quality_histogram": "[0, 2, 10, 18, 56, 101, 108, 97, 63, 36, 41, 60, 100, 164, 255, 284, 287, 195, 135, 36]", - "total_badness": 3675.3946288 + "ne3d": 2060, + "quality_histogram": "[0, 2, 5, 15, 46, 103, 106, 104, 71, 36, 48, 67, 99, 165, 253, 287, 287, 195, 136, 35]", + "total_badness": 3642.1604728 }, { "angles_tet": [ @@ -633,14 +633,14 @@ 154.37 ], "angles_trig": [ - 19.374, + 19.317, 128.1 ], "ne1d": 428, "ne2d": 926, - "ne3d": 1071, - "quality_histogram": "[0, 0, 0, 0, 0, 1, 3, 22, 48, 36, 110, 131, 98, 115, 161, 162, 68, 66, 30, 20]", - "total_badness": 1667.9770545 + "ne3d": 1086, + "quality_histogram": "[0, 0, 0, 0, 0, 1, 3, 22, 44, 37, 108, 133, 101, 117, 167, 161, 67, 71, 33, 21]", + "total_badness": 1684.0903817 } ], "cubemcyl.geo": [ @@ -860,18 +860,18 @@ }, { "angles_tet": [ - 15.925, + 16.061, 157.39 ], "angles_trig": [ - 17.814, + 16.851, 127.45 ], "ne1d": 36, "ne2d": 152, - "ne3d": 381, - "quality_histogram": "[0, 0, 0, 0, 0, 9, 13, 18, 26, 25, 30, 29, 42, 32, 39, 28, 41, 21, 22, 6]", - "total_badness": 648.79536841 + "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 }, { "angles_tet": [ @@ -1014,18 +1014,18 @@ }, { "angles_tet": [ - 5.1577, - 170.71 + 5.7043, + 170.47 ], "angles_trig": [ - 8.073, - 161.81 + 8.0227, + 160.66 ], "ne1d": 0, "ne2d": 192, - "ne3d": 748, - "quality_histogram": "[0, 5, 41, 63, 100, 92, 74, 71, 54, 49, 43, 43, 23, 20, 20, 20, 10, 5, 12, 3]", - "total_badness": 2470.4393077 + "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 }, { "angles_tet": [ @@ -1166,18 +1166,18 @@ }, { "angles_tet": [ - 20.184, + 19.932, 144.83 ], "angles_trig": [ - 21.582, + 21.622, 126.14 ], "ne1d": 432, "ne2d": 9544, - "ne3d": 69863, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 1, 7, 30, 69, 222, 646, 1562, 3675, 7035, 11242, 14646, 15515, 11810, 3403]", - "total_badness": 85648.446235 + "ne3d": 69846, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 1, 7, 30, 71, 221, 652, 1560, 3667, 7029, 11233, 14630, 15524, 11810, 3411]", + "total_badness": 85625.273734 } ], "ellipticcyl.geo": [ @@ -1364,53 +1364,6 @@ "total_badness": 639.78974791 } ], - "frame.step": [ - { - "angles_tet": [ - 2.9095, - 171.1 - ], - "angles_trig": [ - 2.6092, - 172.05 - ], - "ne1d": 10108, - "ne2d": 30160, - "ne3d": 152987, - "quality_histogram": "[0, 3, 1, 3, 6, 20, 57, 149, 535, 1257, 2919, 5827, 10443, 16376, 21793, 26060, 26579, 22897, 14346, 3716]", - "total_badness": 202618.94822 - }, - { - "angles_tet": [ - 2.296, - 175.61 - ], - "angles_trig": [ - 1.8443, - 175.57 - ], - "ne1d": 5988, - "ne2d": 11102, - "ne3d": 29317, - "quality_histogram": "[3, 4, 5, 8, 16, 44, 120, 246, 699, 1024, 1561, 2491, 3110, 3894, 4329, 4296, 3374, 2408, 1353, 332]", - "total_badness": 43465.268618 - }, - { - "angles_tet": [ - 2.5792, - 174.11 - ], - "angles_trig": [ - 2.2053, - 174.13 - ], - "ne1d": 9622, - "ne2d": 23964, - "ne3d": 80994, - "quality_histogram": "[2, 14, 4, 20, 18, 40, 94, 224, 488, 1114, 2412, 4540, 7490, 10250, 12758, 13185, 12021, 9204, 5660, 1456]", - "total_badness": 111934.48598 - } - ], "hinge.stl": [ { "angles_tet": [ @@ -1490,17 +1443,17 @@ { "angles_tet": [ 20.701, - 140.94 + 144.6 ], "angles_trig": [ 22.443, - 122.89 + 122.07 ], "ne1d": 1862, "ne2d": 19474, - "ne3d": 136555, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 1, 12, 59, 278, 860, 2542, 6422, 13021, 21252, 29142, 31120, 24008, 7838]", - "total_badness": 165971.00359 + "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 } ], "lense.in2d": [ @@ -1690,18 +1643,18 @@ "manyholes.geo": [ { "angles_tet": [ - 14.385, + 14.551, 155.18 ], "angles_trig": [ - 13.429, + 16.38, 141.4 ], "ne1d": 5886, "ne2d": 48052, - "ne3d": 178770, - "quality_histogram": "[0, 0, 0, 0, 0, 5, 15, 82, 303, 822, 2352, 6216, 10998, 19000, 27368, 30676, 31225, 26902, 18298, 4508]", - "total_badness": 233986.23978 + "ne3d": 178832, + "quality_histogram": "[0, 0, 0, 0, 0, 5, 11, 72, 289, 828, 2308, 6210, 10937, 18854, 27390, 30600, 31363, 26926, 18496, 4543]", + "total_badness": 233895.88826 }, { "angles_tet": [ @@ -1715,8 +1668,8 @@ "ne1d": 2746, "ne2d": 13866, "ne3d": 29391, - "quality_histogram": "[0, 0, 0, 0, 13, 14, 37, 138, 377, 848, 1450, 2328, 3278, 4286, 4195, 3745, 3323, 2685, 1964, 710]", - "total_badness": 42208.591965 + "quality_histogram": "[0, 0, 0, 0, 13, 14, 37, 136, 380, 846, 1453, 2331, 3276, 4281, 4196, 3749, 3317, 2686, 1967, 709]", + "total_badness": 42208.382479 }, { "angles_tet": [ @@ -1729,9 +1682,9 @@ ], "ne1d": 4106, "ne2d": 27994, - "ne3d": 70783, - "quality_histogram": "[0, 0, 0, 1, 30, 72, 170, 340, 660, 1449, 2616, 4104, 6681, 9272, 10482, 10764, 9861, 7627, 4870, 1784]", - "total_badness": 99055.647638 + "ne3d": 70797, + "quality_histogram": "[0, 0, 0, 1, 30, 72, 170, 340, 665, 1450, 2605, 4080, 6678, 9294, 10482, 10758, 9889, 7627, 4870, 1786]", + "total_badness": 99064.519397 } ], "manyholes2.geo": [ @@ -1746,9 +1699,9 @@ ], "ne1d": 10202, "ne2d": 55380, - "ne3d": 128240, - "quality_histogram": "[0, 0, 0, 0, 4, 29, 79, 237, 725, 1935, 4437, 7722, 11695, 17431, 18582, 18325, 17276, 15158, 10938, 3667]", - "total_badness": 176228.44994 + "ne3d": 128239, + "quality_histogram": "[0, 0, 0, 0, 4, 29, 79, 237, 724, 1933, 4439, 7719, 11694, 17428, 18585, 18328, 17275, 15160, 10938, 3667]", + "total_badness": 176224.09669 } ], "matrix.geo": [ @@ -1763,9 +1716,9 @@ ], "ne1d": 174, "ne2d": 1198, - "ne3d": 5066, - "quality_histogram": "[0, 0, 11, 118, 169, 57, 61, 111, 95, 184, 293, 368, 508, 651, 617, 577, 496, 429, 246, 75]", - "total_badness": 8799.2034431 + "ne3d": 5070, + "quality_histogram": "[0, 0, 11, 117, 166, 59, 60, 113, 98, 185, 297, 374, 498, 658, 620, 577, 494, 424, 240, 79]", + "total_badness": 8804.2621534 }, { "angles_tet": [ @@ -1778,9 +1731,9 @@ ], "ne1d": 106, "ne2d": 610, - "ne3d": 1654, - "quality_histogram": "[0, 1, 12, 50, 83, 156, 195, 155, 160, 124, 137, 141, 133, 102, 67, 34, 32, 43, 24, 5]", - "total_badness": 4104.7339693 + "ne3d": 1658, + "quality_histogram": "[0, 1, 14, 48, 79, 156, 193, 158, 156, 122, 138, 142, 136, 108, 66, 40, 31, 41, 25, 4]", + "total_badness": 4098.9846426 }, { "angles_tet": [ @@ -1808,9 +1761,9 @@ ], "ne1d": 174, "ne2d": 1198, - "ne3d": 5005, - "quality_histogram": "[0, 0, 7, 100, 165, 53, 56, 108, 103, 165, 278, 336, 503, 574, 623, 631, 520, 438, 264, 81]", - "total_badness": 8524.8161998 + "ne3d": 5012, + "quality_histogram": "[0, 0, 7, 101, 161, 60, 53, 107, 93, 172, 281, 320, 519, 570, 616, 653, 509, 445, 260, 85]", + "total_badness": 8527.4907589 }, { "angles_tet": [ @@ -1838,9 +1791,9 @@ ], "ne1d": 418, "ne2d": 5968, - "ne3d": 101047, - "quality_histogram": "[0, 0, 0, 0, 0, 1, 5, 8, 52, 104, 356, 989, 2551, 5548, 10164, 16045, 20725, 22251, 16920, 5328]", - "total_badness": 124081.88321 + "ne3d": 101104, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 4, 7, 52, 103, 348, 992, 2548, 5550, 10212, 16062, 20713, 22250, 16917, 5346]", + "total_badness": 124141.43144 } ], "ortho.geo": [ @@ -2034,29 +1987,29 @@ 162.28 ], "angles_trig": [ - 14.582, + 14.714, 141.01 ], "ne1d": 160, "ne2d": 286, - "ne3d": 590, - "quality_histogram": "[0, 0, 0, 0, 6, 10, 15, 24, 40, 62, 65, 67, 64, 47, 50, 45, 38, 42, 12, 3]", - "total_badness": 1045.1530377 + "ne3d": 598, + "quality_histogram": "[0, 0, 0, 0, 3, 2, 13, 17, 35, 62, 59, 74, 66, 57, 56, 49, 39, 43, 19, 4]", + "total_badness": 1009.5773389 }, { "angles_tet": [ - 12.731, - 162.52 + 11.213, + 163.54 ], "angles_trig": [ - 15.335, - 148.34 + 13.446, + 152.87 ], "ne1d": 232, "ne2d": 598, - "ne3d": 1383, - "quality_histogram": "[0, 0, 0, 1, 13, 17, 35, 53, 69, 92, 121, 143, 146, 153, 154, 121, 115, 84, 52, 14]", - "total_badness": 2341.0219936 + "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 }, { "angles_tet": [ @@ -2116,9 +2069,9 @@ ], "ne1d": 886, "ne2d": 2592, - "ne3d": 8268, - "quality_histogram": "[4, 9, 33, 42, 41, 54, 43, 47, 100, 142, 258, 402, 641, 938, 1253, 1305, 1193, 1022, 588, 153]", - "total_badness": 12309.108485 + "ne3d": 8269, + "quality_histogram": "[4, 9, 33, 44, 40, 53, 44, 46, 101, 142, 258, 402, 641, 938, 1253, 1304, 1193, 1022, 589, 153]", + "total_badness": 12315.265721 }, { "angles_tet": [ @@ -2131,9 +2084,9 @@ ], "ne1d": 570, "ne2d": 1202, - "ne3d": 1823, - "quality_histogram": "[2, 22, 36, 57, 66, 78, 105, 136, 163, 183, 187, 160, 150, 143, 114, 76, 69, 47, 25, 4]", - "total_badness": 4525.5906501 + "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 }, { "angles_tet": [ @@ -2162,8 +2115,8 @@ "ne1d": 956, "ne2d": 2828, "ne3d": 8577, - "quality_histogram": "[3, 9, 37, 48, 48, 52, 58, 60, 87, 127, 205, 328, 507, 805, 1199, 1394, 1476, 1215, 736, 183]", - "total_badness": 12579.939101 + "quality_histogram": "[3, 9, 37, 48, 48, 52, 57, 61, 87, 129, 205, 326, 507, 804, 1200, 1394, 1476, 1215, 736, 183]", + "total_badness": 12580.561684 }, { "angles_tet": [ @@ -2176,9 +2129,9 @@ ], "ne1d": 1554, "ne2d": 6372, - "ne3d": 31588, - "quality_histogram": "[2, 7, 14, 6, 25, 55, 52, 67, 91, 190, 307, 635, 1249, 2307, 3892, 5308, 6146, 5974, 4098, 1163]", - "total_badness": 40793.027008 + "ne3d": 31607, + "quality_histogram": "[2, 7, 14, 7, 26, 53, 50, 67, 90, 188, 312, 638, 1249, 2301, 3886, 5314, 6167, 5965, 4114, 1157]", + "total_badness": 40813.948339 }, { "angles_tet": [ @@ -2191,9 +2144,9 @@ ], "ne1d": 2992, "ne2d": 23322, - "ne3d": 281957, - "quality_histogram": "[4, 9, 10, 11, 11, 21, 33, 65, 96, 260, 755, 2146, 5563, 13605, 27734, 44577, 59933, 63963, 48268, 14893]", - "total_badness": 344644.09939 + "ne3d": 281901, + "quality_histogram": "[4, 10, 12, 10, 9, 21, 29, 61, 95, 247, 747, 2145, 5539, 13549, 27678, 44557, 59948, 64037, 48291, 14912]", + "total_badness": 344516.23097 } ], "revolution.geo": [ @@ -2288,53 +2241,6 @@ "total_badness": 244286.77424 } ], - "screw.step": [ - { - "angles_tet": [ - 15.139, - 148.36 - ], - "angles_trig": [ - 17.363, - 140.59 - ], - "ne1d": 400, - "ne2d": 1436, - "ne3d": 2342, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 16, 61, 92, 165, 209, 246, 307, 280, 262, 272, 182, 148, 84, 18]", - "total_badness": 3718.1755695 - }, - { - "angles_tet": [ - 21.55, - 146.38 - ], - "angles_trig": [ - 17.221, - 126.09 - ], - "ne1d": 528, - "ne2d": 2792, - "ne3d": 8129, - "quality_histogram": "[0, 0, 0, 0, 0, 1, 4, 8, 35, 96, 188, 298, 537, 817, 1057, 1323, 1446, 1284, 798, 237]", - "total_badness": 10753.086327 - }, - { - "angles_tet": [ - 20.515, - 144.03 - ], - "angles_trig": [ - 24.891, - 120.48 - ], - "ne1d": 666, - "ne2d": 4922, - "ne3d": 31540, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 1, 5, 31, 92, 290, 707, 1762, 3221, 4997, 6712, 6966, 5146, 1610]", - "total_badness": 38689.280913 - } - ], "sculpture.geo": [ { "angles_tet": [ @@ -2417,31 +2323,31 @@ 147.57 ], "angles_trig": [ - 16.998, + 17.184, 119.06 ], "ne1d": 480, "ne2d": 2394, "ne3d": 6711, - "quality_histogram": "[0, 0, 0, 0, 1, 2, 5, 9, 18, 27, 60, 127, 255, 455, 730, 1074, 1345, 1332, 952, 319]", - "total_badness": 8467.8828851 + "quality_histogram": "[0, 0, 0, 0, 2, 2, 7, 8, 21, 26, 61, 123, 262, 462, 722, 1073, 1348, 1317, 960, 317]", + "total_badness": 8476.8430085 } ], "shaft.geo": [ { "angles_tet": [ - 9.1003, - 164.73 + 8.3002, + 162.65 ], "angles_trig": [ - 9.2165, - 146.85 + 9.3888, + 147.77 ], "ne1d": 708, "ne2d": 1722, - "ne3d": 2725, - "quality_histogram": "[0, 0, 3, 6, 15, 19, 28, 47, 87, 138, 286, 386, 316, 291, 250, 298, 242, 178, 104, 31]", - "total_badness": 4420.5345142 + "ne3d": 2740, + "quality_histogram": "[0, 0, 1, 5, 8, 15, 31, 39, 87, 146, 294, 392, 329, 286, 245, 291, 247, 185, 108, 31]", + "total_badness": 4403.8888129 }, { "angles_tet": [ @@ -2460,18 +2366,18 @@ }, { "angles_tet": [ - 7.5703, - 165.31 + 12.907, + 159.86 ], "angles_trig": [ - 12.063, - 152.34 + 11.963, + 148.8 ], "ne1d": 510, "ne2d": 1004, - "ne3d": 1832, - "quality_histogram": "[0, 0, 2, 8, 9, 35, 44, 79, 84, 110, 107, 164, 159, 194, 235, 212, 202, 104, 66, 18]", - "total_badness": 3083.8429043 + "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 }, { "angles_tet": [ @@ -2479,14 +2385,14 @@ 162.65 ], "angles_trig": [ - 14.459, - 150.06 + 15.525, + 147.01 ], "ne1d": 708, "ne2d": 1722, - "ne3d": 2703, - "quality_histogram": "[0, 0, 0, 0, 2, 3, 11, 17, 48, 118, 246, 396, 350, 292, 274, 307, 281, 221, 102, 35]", - "total_badness": 4122.3827179 + "ne3d": 2713, + "quality_histogram": "[0, 0, 0, 1, 3, 1, 11, 22, 49, 109, 260, 408, 344, 300, 273, 303, 272, 215, 106, 36]", + "total_badness": 4151.3073463 }, { "angles_tet": [ @@ -2644,18 +2550,18 @@ }, { "angles_tet": [ - 8.1657, - 165.53 + 9.1579, + 165.65 ], "angles_trig": [ - 9.2408, - 143.87 + 8.211, + 143.3 ], "ne1d": 30, "ne2d": 116, - "ne3d": 262, - "quality_histogram": "[0, 0, 4, 26, 30, 52, 33, 16, 22, 13, 11, 12, 11, 8, 6, 7, 6, 3, 2, 0]", - "total_badness": 832.73325512 + "ne3d": 264, + "quality_histogram": "[0, 0, 7, 21, 33, 55, 37, 14, 20, 15, 10, 6, 13, 10, 6, 7, 5, 3, 2, 0]", + "total_badness": 850.25370446 }, { "angles_tet": [ @@ -2997,18 +2903,18 @@ }, { "angles_tet": [ - 1.7223, - 174.81 + 1.6657, + 174.24 ], "angles_trig": [ - 4.9314, - 166.92 + 4.1081, + 164.43 ], "ne1d": 0, "ne2d": 692, - "ne3d": 2691, - "quality_histogram": "[26, 258, 398, 331, 349, 264, 205, 192, 123, 145, 87, 67, 74, 48, 30, 33, 29, 20, 11, 1]", - "total_badness": 14056.890733 + "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.68014 }, { "angles_tet": [ @@ -3079,18 +2985,18 @@ ], "angles_trig": [ 14.916, - 132.02 + 130.79 ], "ne1d": 690, "ne2d": 1684, - "ne3d": 5193, - "quality_histogram": "[0, 0, 1, 1, 1, 11, 32, 47, 111, 196, 275, 365, 465, 566, 668, 699, 617, 545, 452, 141]", - "total_badness": 7518.4794095 + "ne3d": 5186, + "quality_histogram": "[0, 0, 1, 0, 0, 9, 26, 34, 106, 192, 291, 357, 463, 570, 662, 695, 628, 542, 471, 139]", + "total_badness": 7461.9914431 }, { "angles_tet": [ - 8.1301, - 160.14 + 8.0938, + 167.14 ], "angles_trig": [ 7.7605, @@ -3098,9 +3004,9 @@ ], "ne1d": 390, "ne2d": 522, - "ne3d": 1353, - "quality_histogram": "[0, 0, 3, 13, 12, 38, 80, 115, 128, 149, 170, 126, 139, 107, 87, 85, 54, 34, 11, 2]", - "total_badness": 2731.8393348 + "ne3d": 1349, + "quality_histogram": "[0, 0, 4, 13, 12, 41, 78, 115, 124, 147, 169, 127, 141, 104, 86, 86, 55, 34, 11, 2]", + "total_badness": 2729.6156372 }, { "angles_tet": [ @@ -3113,9 +3019,9 @@ ], "ne1d": 512, "ne2d": 874, - "ne3d": 2381, - "quality_histogram": "[0, 0, 0, 3, 9, 15, 42, 68, 122, 139, 198, 209, 307, 380, 349, 235, 137, 97, 46, 25]", - "total_badness": 3929.5802554 + "ne3d": 2382, + "quality_histogram": "[0, 0, 0, 3, 9, 13, 41, 68, 124, 140, 196, 215, 305, 390, 343, 237, 128, 98, 47, 25]", + "total_badness": 3929.8055104 }, { "angles_tet": [ @@ -3124,18 +3030,18 @@ ], "angles_trig": [ 14.916, - 132.02 + 130.79 ], "ne1d": 690, "ne2d": 1684, - "ne3d": 5099, - "quality_histogram": "[0, 0, 1, 1, 0, 3, 23, 37, 102, 189, 265, 343, 430, 564, 673, 707, 612, 543, 465, 141]", - "total_badness": 7304.8063731 + "ne3d": 5110, + "quality_histogram": "[0, 0, 1, 0, 0, 4, 18, 33, 104, 176, 266, 350, 443, 555, 682, 703, 613, 551, 468, 143]", + "total_badness": 7297.2366495 }, { "angles_tet": [ - 6.8825, - 166.88 + 16.895, + 145.94 ], "angles_trig": [ 17.568, @@ -3143,13 +3049,13 @@ ], "ne1d": 1050, "ne2d": 3812, - "ne3d": 17990, - "quality_histogram": "[0, 0, 1, 0, 0, 0, 3, 15, 34, 64, 183, 570, 1424, 2206, 2299, 2682, 2720, 2713, 2367, 709]", - "total_badness": 23464.671179 + "ne3d": 18010, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 3, 15, 34, 61, 181, 572, 1425, 2192, 2302, 2698, 2704, 2739, 2390, 694]", + "total_badness": 23478.48161 }, { "angles_tet": [ - 14.338, + 15.34, 149.41 ], "angles_trig": [ @@ -3158,26 +3064,26 @@ ], "ne1d": 1722, "ne2d": 10042, - "ne3d": 84837, - "quality_histogram": "[0, 0, 0, 0, 0, 3, 55, 1435, 719, 373, 691, 1186, 2492, 5459, 8935, 13171, 16437, 16966, 12825, 4090]", - "total_badness": 108583.90765 + "ne3d": 84793, + "quality_histogram": "[0, 0, 0, 0, 0, 2, 50, 1428, 718, 373, 701, 1171, 2465, 5462, 8878, 13214, 16426, 16935, 12864, 4106]", + "total_badness": 108481.65242 } ], "twobricks.geo": [ { "angles_tet": [ - 22.934, - 142.89 + 25.655, + 137.37 ], "angles_trig": [ - 18.806, - 142.29 + 23.972, + 121.23 ], "ne1d": 72, "ne2d": 50, - "ne3d": 41, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 8, 2, 16, 3, 4, 0, 0, 0, 0]", - "total_badness": 68.897088924 + "ne3d": 43, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 5, 6, 3, 16, 3, 6, 1, 1, 0, 0]", + "total_badness": 67.089294311 }, { "angles_tet": [ @@ -3211,18 +3117,18 @@ }, { "angles_tet": [ - 22.934, - 142.89 + 25.655, + 137.37 ], "angles_trig": [ - 18.806, - 142.29 + 23.971, + 121.23 ], "ne1d": 72, "ne2d": 50, - "ne3d": 41, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 8, 2, 16, 3, 4, 0, 0, 0, 0]", - "total_badness": 68.897088924 + "ne3d": 43, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 5, 6, 3, 16, 3, 6, 1, 1, 0, 0]", + "total_badness": 67.089294246 }, { "angles_tet": [ @@ -3252,24 +3158,24 @@ "ne2d": 346, "ne3d": 595, "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 23, 40, 55, 95, 101, 105, 99, 60, 8]", - "total_badness": 777.63275563 + "total_badness": 777.63275434 } ], "twocubes.geo": [ { "angles_tet": [ - 22.934, - 142.89 + 25.655, + 137.37 ], "angles_trig": [ - 18.806, - 142.29 + 23.972, + 121.23 ], "ne1d": 72, "ne2d": 50, - "ne3d": 41, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 8, 2, 16, 3, 4, 0, 0, 0, 0]", - "total_badness": 68.897088924 + "ne3d": 43, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 5, 6, 3, 16, 3, 6, 1, 1, 0, 0]", + "total_badness": 67.089294311 }, { "angles_tet": [ @@ -3303,18 +3209,18 @@ }, { "angles_tet": [ - 22.934, - 142.89 + 25.655, + 137.37 ], "angles_trig": [ - 18.806, - 142.29 + 23.971, + 121.23 ], "ne1d": 72, "ne2d": 50, - "ne3d": 41, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 8, 2, 16, 3, 4, 0, 0, 0, 0]", - "total_badness": 68.897088924 + "ne3d": 43, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 5, 6, 3, 16, 3, 6, 1, 1, 0, 0]", + "total_badness": 67.089294246 }, { "angles_tet": [ @@ -3344,7 +3250,7 @@ "ne2d": 346, "ne3d": 595, "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 23, 40, 55, 95, 101, 105, 99, 60, 8]", - "total_badness": 777.63275563 + "total_badness": 777.63275434 } ], "twocyl.geo": [ From 2f88502729363011f6127395f5ff2c9bb752220e Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Thu, 23 Jul 2020 16:01:34 +0200 Subject: [PATCH 076/384] Remove Segment::bcname, fix Mesh::operator= Remap the 'string* bcname' members in the FaceDescriptor objects in Mesh::operator= to the new mesh --- libsrc/geom2d/genmesh2d.cpp | 3 --- libsrc/interface/nginterface.cpp | 2 +- libsrc/interface/readuser.cpp | 5 ----- libsrc/meshing/meshclass.cpp | 33 +++++++++----------------------- libsrc/meshing/meshtype.cpp | 7 ++----- libsrc/meshing/meshtype.hpp | 19 ------------------ 6 files changed, 12 insertions(+), 57 deletions(-) diff --git a/libsrc/geom2d/genmesh2d.cpp b/libsrc/geom2d/genmesh2d.cpp index c1eadf1a..6d00f1fe 100644 --- a/libsrc/geom2d/genmesh2d.cpp +++ b/libsrc/geom2d/genmesh2d.cpp @@ -458,9 +458,6 @@ namespace netgen for ( int sindex = 0; sindex < maxsegmentindex; sindex++ ) mesh->SetBCName ( sindex, geometry.GetBCName( sindex+1 ) ); - for (SegmentIndex si = 0; si < mesh->GetNSeg(); si++) - (*mesh)[si].SetBCName ( (*mesh).GetBCNamePtr( (*mesh)[si].si-1 ) ); - mesh->CalcLocalH(mp.grading); int bnp = mesh->GetNP(); // boundary points diff --git a/libsrc/interface/nginterface.cpp b/libsrc/interface/nginterface.cpp index 7c647119..42d26094 100644 --- a/libsrc/interface/nginterface.cpp +++ b/libsrc/interface/nginterface.cpp @@ -560,7 +560,7 @@ char * Ng_GetSurfaceElementBCName (int ei) if ( mesh->GetDimension() == 3 ) return const_cast(mesh->GetFaceDescriptor(mesh->SurfaceElement(ei).GetIndex()).GetBCName().c_str()); else - return const_cast(mesh->LineSegment(ei).GetBCName().c_str()); + return const_cast(mesh->GetBCName(mesh->LineSegment(ei).si).c_str()); } diff --git a/libsrc/interface/readuser.cpp b/libsrc/interface/readuser.cpp index d3d50cf2..29b16afa 100644 --- a/libsrc/interface/readuser.cpp +++ b/libsrc/interface/readuser.cpp @@ -313,7 +313,6 @@ namespace netgen ednr = mesh.AddEdgeDescriptor(ed); mesh.SetCD2Name(bcpr, name); auto nr = mesh.AddSegment(tmp_segments[get<0>(element_map[index])-1]); - mesh[nr].SetBCName(mesh.GetCD2NamePtr(mesh.GetNCD2Names())); mesh[nr].edgenr = ednr+1; } else if(dim == 2) @@ -321,7 +320,6 @@ namespace netgen Segment & seg = mesh.LineSegment(get<0>(element_map[index])); seg.si = bccounter + 1; mesh.SetBCName(bccounter, name); - seg.SetBCName(mesh.GetBCNamePtr(bccounter)); bccounter++; } break; @@ -353,13 +351,11 @@ namespace netgen { auto nr = mesh.AddSegment(tmp_segments[get<0>(element_map[index])-1]); mesh[nr].edgenr = ednr+1; - mesh[nr].SetBCName(mesh.GetCD2NamePtr(mesh.GetNCD2Names())); } else if(dim == 2) { Segment & seg = mesh.LineSegment(get<0>(element_map[index])); seg.si = bccounter; - seg.SetBCName(mesh.GetBCNamePtr(bccounter-1)); } break; default: @@ -388,7 +384,6 @@ namespace netgen if(seg.si == -1){ seg.si = bccounter + 1; if(bccounter_tmp == bccounter) mesh.SetBCName(bccounter, "default"); // could be more efficient - seg.SetBCName(mesh.GetBCNamePtr(bccounter)); bccounter_tmp++; } } diff --git a/libsrc/meshing/meshclass.cpp b/libsrc/meshing/meshclass.cpp index 76a22ffc..703109a1 100644 --- a/libsrc/meshing/meshclass.cpp +++ b/libsrc/meshing/meshclass.cpp @@ -105,11 +105,18 @@ namespace netgen if ( mesh2.materials[i] ) materials[i] = new string ( *mesh2.materials[i] ); else materials[i] = 0; - + std::map bcmap; bcnames.SetSize( mesh2.bcnames.Size() ); for ( int i = 0; i < mesh2.bcnames.Size(); i++ ) + { if ( mesh2.bcnames[i] ) bcnames[i] = new string ( *mesh2.bcnames[i] ); else bcnames[i] = 0; + bcmap[mesh2.bcnames[i]] = bcnames[i]; + } + + // Remap string* members in FaceDescriptor to new mesh + for (auto & f : facedecoding) + f.SetBCName( bcmap[&f.GetBCName()] ); cd2names.SetSize(mesh2.cd2names.Size()); @@ -1112,18 +1119,7 @@ namespace netgen bcnames[bcnrs[i-1]-1] = new string(nextbcname); } - if ( GetDimension() == 2 ) - { - for (i = 1; i <= GetNSeg(); i++) - { - Segment & seg = LineSegment (i); - if ( seg.si <= n ) - seg.SetBCName (bcnames[seg.si-1]); - else - seg.SetBCName(0); - } - } - else + if ( GetDimension() == 3 ) { for (SurfaceElementIndex sei = 0; sei < GetNSE(); sei++) { @@ -1156,17 +1152,6 @@ namespace netgen { throw NgException("co dim 2 elements not implemented for dimension 2"); } - else - { - for (i = 1; i<= GetNSeg(); i++) - { - Segment & seg = LineSegment(i); - if ( seg.edgenr <= n ) - seg.SetBCName (cd2names[seg.edgenr-1]); - else - seg.SetBCName(0); - } - } } if (strcmp (str, "singular_points") == 0) diff --git a/libsrc/meshing/meshtype.cpp b/libsrc/meshing/meshtype.cpp index 9523fab7..f512c683 100644 --- a/libsrc/meshing/meshtype.cpp +++ b/libsrc/meshing/meshtype.cpp @@ -80,8 +80,6 @@ namespace netgen epgeominfo[1].edgenr = 1; epgeominfo[1].dist = 0; */ - - bcname = nullptr; } Segment::Segment (const Segment & other) @@ -109,7 +107,6 @@ namespace netgen geominfo[1] = other.geominfo[1]; epgeominfo[0] = other.epgeominfo[0]; epgeominfo[1] = other.epgeominfo[1]; - bcname = other.bcname; } Segment& Segment::operator=(const Segment & other) @@ -135,7 +132,6 @@ namespace netgen pnums[2] = other.pnums[2]; meshdocval = other.meshdocval; hp_elnr = other.hp_elnr; - bcname = other.bcname; is_curved = other.is_curved; } @@ -144,11 +140,12 @@ namespace netgen void Segment :: DoArchive (Archive & ar) { + string * bcname_dummy = nullptr; ar & pnums[0] & pnums[1] & pnums[2] & edgenr & singedge_left & singedge_right & si & cd2i & domin & domout & tlosurf & surfnr1 & surfnr2 - & bcname + & bcname_dummy // keep this for backward compatiblity & epgeominfo[0].edgenr & epgeominfo[1].edgenr; } diff --git a/libsrc/meshing/meshtype.hpp b/libsrc/meshing/meshtype.hpp index e6ccc83e..84e9aec8 100644 --- a/libsrc/meshing/meshtype.hpp +++ b/libsrc/meshing/meshtype.hpp @@ -1031,7 +1031,6 @@ namespace netgen // #endif private: - string* bcname; bool is_curved; public: @@ -1048,24 +1047,6 @@ namespace netgen int hp_elnr; - void SetBCName ( string * abcname ) - { - bcname = abcname; - } - - string * BCNamePtr () - { return bcname; } - - const string * BCNamePtr () const - { return bcname; } - - const string & GetBCName () const - { - static string defaultstring = "default"; - if (! bcname ) return defaultstring; - return *bcname; - } - int GetNP() const { return pnums[2].IsValid() ? 3 : 2; From dcc0484be05ff099f9daddfca8edf8056f103679 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Thu, 23 Jul 2020 16:24:22 +0200 Subject: [PATCH 077/384] install netgen_version.hpp, set version in Archive --- CMakeLists.txt | 1 + cmake/generate_version_file.cmake | 12 +++++++++++- libsrc/core/archive.cpp | 7 +++++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index db13de81..86aac285 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -79,6 +79,7 @@ endif() set(CMAKE_EXPORT_COMPILE_COMMANDS ON) include (${CMAKE_CURRENT_LIST_DIR}/cmake/generate_version_file.cmake) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/netgen_version.hpp DESTINATION ${NG_INSTALL_DIR_INCLUDE}/include COMPONENT netgen_devel) set(CPACK_PACKAGE_VERSION "${NETGEN_VERSION}") diff --git a/cmake/generate_version_file.cmake b/cmake/generate_version_file.cmake index 3b913636..eb1a5e35 100644 --- a/cmake/generate_version_file.cmake +++ b/cmake/generate_version_file.cmake @@ -36,7 +36,17 @@ endif() set(NETGEN_VERSION_LONG ${NETGEN_VERSION_SHORT}-${NETGEN_VERSION_TWEAK}-${NETGEN_VERSION_HASH}) set(version_file ${BDIR}/netgen_version.hpp) -set(new_version_file_string "#define NETGEN_VERSION \"${NETGEN_VERSION}\"\n") +set(new_version_file_string "\ +#ifndef NETGEN_VERSION_HPP_INCLUDED +#define NETGEN_VERSION_HPP_INCLUDED +#define NETGEN_VERSION \"${NETGEN_VERSION}\" +#define NETGEN_VERSION_MAJOR ${NETGEN_VERSION_MAJOR} +#define NETGEN_VERSION_MINOR ${NETGEN_VERSION_MINOR} +#define NETGEN_VERSION_PATCH ${NETGEN_VERSION_PATCH} +#define NETGEN_VERSION_TWEAK ${NETGEN_VERSION_TWEAK} +#define NETGEN_VERSION_HASH \"${NETGEN_VERSION_HASH}\" +#endif // NETGEN_VERSION_HPP_INCLUDED +") if(EXISTS ${version_file}) file(READ ${version_file} old_version_file_string ) if(${old_version_file_string} STREQUAL ${new_version_file_string}) diff --git a/libsrc/core/archive.cpp b/libsrc/core/archive.cpp index 84e6d875..5d968b6c 100644 --- a/libsrc/core/archive.cpp +++ b/libsrc/core/archive.cpp @@ -1,5 +1,6 @@ #include "archive.hpp" +#include #ifndef WIN32 #include @@ -44,4 +45,10 @@ namespace ngcore std::make_unique>(); return type_register->count(classname) != 0; } + + + static bool dummy = [](){ + SetLibraryVersion("netgen", NETGEN_VERSION); + return true; + }(); } // namespace ngcore From 829ff0aa535f51680f9ec7f19110a64364e1b0f6 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Thu, 23 Jul 2020 17:49:10 +0200 Subject: [PATCH 078/384] fix install of netgen_version.hpp --- CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 86aac285..d6197b45 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -79,7 +79,6 @@ endif() set(CMAKE_EXPORT_COMPILE_COMMANDS ON) include (${CMAKE_CURRENT_LIST_DIR}/cmake/generate_version_file.cmake) -install(FILES ${CMAKE_CURRENT_BINARY_DIR}/netgen_version.hpp DESTINATION ${NG_INSTALL_DIR_INCLUDE}/include COMPONENT netgen_devel) set(CPACK_PACKAGE_VERSION "${NETGEN_VERSION}") @@ -405,6 +404,8 @@ if(USE_CGNS) endif(NOT WIN32 AND NOT APPLE) endif(USE_CGNS) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/netgen_version.hpp DESTINATION ${NG_INSTALL_DIR_INCLUDE}/include COMPONENT netgen_devel) + add_subdirectory(libsrc) add_subdirectory(ng) add_subdirectory(tutorials) From f73159e35a4b992a0f156bef6213d7fa103275c0 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Thu, 23 Jul 2020 19:04:21 +0200 Subject: [PATCH 079/384] Set version of Netgen globally (for archives), interface to get version --- libsrc/core/CMakeLists.txt | 1 + libsrc/core/archive.cpp | 20 +------------------- libsrc/core/archive.hpp | 6 ------ libsrc/core/python_ngcore.hpp | 4 ++-- libsrc/core/version.cpp | 29 +++++++++++++++++++++++++++++ libsrc/core/version.hpp | 8 ++++++++ 6 files changed, 41 insertions(+), 27 deletions(-) create mode 100644 libsrc/core/version.cpp diff --git a/libsrc/core/CMakeLists.txt b/libsrc/core/CMakeLists.txt index f0f07399..16c43a82 100644 --- a/libsrc/core/CMakeLists.txt +++ b/libsrc/core/CMakeLists.txt @@ -11,6 +11,7 @@ add_library(ngcore SHARED table.cpp taskmanager.cpp utils.cpp + version.cpp ) # Pybind11 2.3 Issue https://github.com/pybind/pybind11/issues/1604 diff --git a/libsrc/core/archive.cpp b/libsrc/core/archive.cpp index 5d968b6c..448b8f47 100644 --- a/libsrc/core/archive.cpp +++ b/libsrc/core/archive.cpp @@ -1,6 +1,6 @@ #include "archive.hpp" -#include +#include "version.hpp" #ifndef WIN32 #include @@ -8,18 +8,6 @@ namespace ngcore { - // clang-tidy should ignore this static object - static std::map library_versions; // NOLINT - std::map& Archive :: GetLibraryVersions() - { - return library_versions; - } - const VersionInfo& GetLibraryVersion(const std::string& library) - { return library_versions[library]; } - - void SetLibraryVersion(const std::string& library, const VersionInfo& version) - { library_versions[library] = version; } - // clang-tidy should ignore this static object static std::unique_ptr> type_register; // NOLINT const detail::ClassArchiveInfo& Archive :: GetArchiveRegister(const std::string& classname) @@ -45,10 +33,4 @@ namespace ngcore std::make_unique>(); return type_register->count(classname) != 0; } - - - static bool dummy = [](){ - SetLibraryVersion("netgen", NETGEN_VERSION); - return true; - }(); } // namespace ngcore diff --git a/libsrc/core/archive.hpp b/libsrc/core/archive.hpp index 22019302..ad4d5676 100644 --- a/libsrc/core/archive.hpp +++ b/libsrc/core/archive.hpp @@ -30,9 +30,6 @@ namespace pybind11 namespace ngcore { - // Libraries using this archive can store their version here to implement backwards compatibility - NGCORE_API const VersionInfo& GetLibraryVersion(const std::string& library); - NGCORE_API void SetLibraryVersion(const std::string& library, const VersionInfo& version); class NGCORE_API Archive; @@ -570,9 +567,6 @@ namespace ngcore virtual void FlushBuffer() {} - protected: - static std::map& GetLibraryVersions(); - private: template friend class RegisterClassForArchive; diff --git a/libsrc/core/python_ngcore.hpp b/libsrc/core/python_ngcore.hpp index a8ef5755..6bedabf9 100644 --- a/libsrc/core/python_ngcore.hpp +++ b/libsrc/core/python_ngcore.hpp @@ -230,7 +230,6 @@ namespace ngcore using ARCHIVE::stream; using ARCHIVE::version_map; using ARCHIVE::logger; - using ARCHIVE::GetLibraryVersions; public: PyArchive(const pybind11::object& alst = pybind11::none()) : ARCHIVE(std::make_shared()), @@ -275,10 +274,11 @@ namespace ngcore pybind11::list WriteOut() { + auto version_runtime = GetLibraryVersions(); FlushBuffer(); lst.append(pybind11::bytes(std::static_pointer_cast(stream)->str())); stream = std::make_shared(); - *this & GetLibraryVersions(); + *this & version_runtime; FlushBuffer(); lst.append(pybind11::bytes(std::static_pointer_cast(stream)->str())); stream = std::make_shared(); diff --git a/libsrc/core/version.cpp b/libsrc/core/version.cpp new file mode 100644 index 00000000..546abbf7 --- /dev/null +++ b/libsrc/core/version.cpp @@ -0,0 +1,29 @@ +#include + +#include +#include "exception.hpp" +#include "version.hpp" + +namespace ngcore +{ + // clang-tidy should ignore this static object + static std::map library_versions; // NOLINT + + const VersionInfo& GetLibraryVersion(const std::string& library) + { return library_versions[library]; } + + const std::map& GetLibraryVersions() + { return library_versions; } + + void SetLibraryVersion(const std::string& library, const VersionInfo& version) + { + if(library_versions.count(library) && (library_versions[library] != version)) + throw Exception("Failed to set library version for " + library + " to " + version.to_string() + ": version already set to " + library_versions[library].to_string()); + library_versions[library] = version; + } + + static bool dummy = [](){ + SetLibraryVersion("netgen", NETGEN_VERSION); + return true; + }(); +} // namespace ngcore diff --git a/libsrc/core/version.hpp b/libsrc/core/version.hpp index aea50bf6..3048ce5b 100644 --- a/libsrc/core/version.hpp +++ b/libsrc/core/version.hpp @@ -80,6 +80,10 @@ namespace ngcore return mayor_ == other.mayor_ && minor_ == other.minor_ && release == other.release && patch == other.patch; } + bool operator !=(const VersionInfo& other) const + { + return !(*this==other); + } bool operator >(const VersionInfo& other) const { return other < (*this); } bool operator <=(const VersionInfo& other) const { return !((*this) > other); } bool operator >=(const VersionInfo& other) const { return !((*this) < other); } @@ -89,6 +93,10 @@ namespace ngcore { return ost << version.to_string(); } + + NGCORE_API const VersionInfo& GetLibraryVersion(const std::string& library); + NGCORE_API const std::map& GetLibraryVersions(); + NGCORE_API void SetLibraryVersion(const std::string& library, const VersionInfo& version); } // namespace ngcore #endif // NETGEN_CORE_VERSION_HPP From 3305d1101a9df24b9a2aba331e9b45009abc0dfc Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Thu, 23 Jul 2020 19:04:36 +0200 Subject: [PATCH 080/384] Store Netgen version in generated mesh files --- libsrc/meshing/meshclass.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libsrc/meshing/meshclass.cpp b/libsrc/meshing/meshclass.cpp index 703109a1..ea30e5f6 100644 --- a/libsrc/meshing/meshclass.cpp +++ b/libsrc/meshing/meshclass.cpp @@ -435,6 +435,7 @@ namespace netgen int inverttets = 0; // globflags.GetDefineFlag ("inverttets"); int invertsurf = 0; // globflags.GetDefineFlag ("invertsurfacemesh"); + outfile << "# Generated by NETGEN " << GetLibraryVersion("netgen") << endl << endl; outfile << "mesh3d" << "\n"; From 68f56058664bb34cf045327ae63785ece5a9d887 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Fri, 24 Jul 2020 17:13:22 +0200 Subject: [PATCH 081/384] Fix version parsing in conda build --- cmake/generate_version_file.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/generate_version_file.cmake b/cmake/generate_version_file.cmake index eb1a5e35..5745e2db 100644 --- a/cmake/generate_version_file.cmake +++ b/cmake/generate_version_file.cmake @@ -4,7 +4,7 @@ endif() find_package(Git REQUIRED) -if(GIT_FOUND AND EXISTS ${CMAKE_CURRENT_LIST_DIR}/../.git) +if(GIT_FOUND AND IS_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/../.git) execute_process(COMMAND git describe --tags --match "v[0-9]*" --long --dirty WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} OUTPUT_VARIABLE git_version_string) else() # for source package files (generated for ubuntu builds on launchpad) read the version from version.txt From fa1a5d11eeb596b6a9f829247cc6d4a0135024ca Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Sat, 25 Jul 2020 08:41:17 +0200 Subject: [PATCH 082/384] Fix version file generation --- cmake/generate_version_file.cmake | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/cmake/generate_version_file.cmake b/cmake/generate_version_file.cmake index 5745e2db..de709298 100644 --- a/cmake/generate_version_file.cmake +++ b/cmake/generate_version_file.cmake @@ -3,16 +3,20 @@ if(NOT BDIR) endif() find_package(Git REQUIRED) +execute_process(COMMAND git describe --tags --match "v[0-9]*" --long --dirty WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} OUTPUT_VARIABLE git_version_string RESULT_VARIABLE status ERROR_QUIET) -if(GIT_FOUND AND IS_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/../.git) - execute_process(COMMAND git describe --tags --match "v[0-9]*" --long --dirty WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} OUTPUT_VARIABLE git_version_string) -else() - # for source package files (generated for ubuntu builds on launchpad) read the version from version.txt +if(status AND NOT status EQUAL 0) if(EXISTS ${CMAKE_CURRENT_LIST_DIR}/../version.txt) - file(READ ${CMAKE_CURRENT_LIST_DIR}/../version.txt git_version_string ) + # for source package files (generated for ubuntu builds on launchpad) read the version from version.txt + if(EXISTS ${CMAKE_CURRENT_LIST_DIR}/../version.txt) + file(READ ${CMAKE_CURRENT_LIST_DIR}/../version.txt git_version_string ) + else() + get_filename_component(git_version_string ${CMAKE_CURRENT_LIST_DIR}/.. NAME) + string(REGEX REPLACE "^netgen(.*)" "\\1" git_version_string "${git_version_string}") + endif() else() - get_filename_component(git_version_string ${CMAKE_CURRENT_LIST_DIR}/.. NAME) - string(REGEX REPLACE "^netgen(.*)" "\\1" git_version_string "${git_version_string}") + MESSAGE(WARNING "Could not determine git-version from source code - assuming 6.2.0.0") + set(git_version_string "v6.2.0.0") endif() endif() From 2744d629358d9784900a2876fe0fe2baa39e4f19 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Sat, 25 Jul 2020 08:46:46 +0200 Subject: [PATCH 083/384] pybind11-stubgen - use python module instead of standalone program --- python/CMakeLists.txt | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index bcbf0a35..a64e54b7 100644 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -9,13 +9,13 @@ install(FILES # build stub files for pybind11 packages if(BUILD_STUB_FILES) -find_program(PYBIND11_STUBS NAMES pybind11-stubgen) -if(PYBIND11_STUBS) - message("-- Found pybind11-stubgen: ${PYBIND11_STUBS}") - install(CODE "execute_process(COMMAND ${PYBIND11_STUBS} --no-setup-py netgen)") - install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../stubs/netgen-stubs/ DESTINATION ${NG_INSTALL_DIR_PYTHON}/netgen/ COMPONENT netgen) -else(PYBIND11_STUBS) +execute_process(COMMAND ${PYTHON_EXECUTABLE} -c "import pybind11_stubgen; print(pybind11_stubgen.__file__)" OUTPUT_VARIABLE stubgen_path RESULT_VARIABLE pybind11_stubgen) +if(pybind11_stubgen AND NOT ${pybind11_stubgen} EQUAL 0) message(WARNING "pybind11-stubgen not found, if you want to create stub files for better autocompletion support install it with pip.") -endif(PYBIND11_STUBS) +else() + message("-- Found pybind11-stubgen: ${stubgen_path}") + install(CODE "execute_process(COMMAND ${PYTHON_EXEcUTABLE} -m pybind11_stubgen --no-setup-py netgen)") + install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../stubs/netgen-stubs/ DESTINATION ${NG_INSTALL_DIR_PYTHON}/netgen/ COMPONENT netgen) +endif() endif(BUILD_STUB_FILES) From f864e53090980f8c9fed2a2c3d6dcc878595c57a Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Sat, 25 Jul 2020 13:04:18 +0200 Subject: [PATCH 084/384] [cmake] fix typo --- python/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index a64e54b7..47910190 100644 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -15,7 +15,7 @@ if(pybind11_stubgen AND NOT ${pybind11_stubgen} EQUAL 0) for better autocompletion support install it with pip.") else() message("-- Found pybind11-stubgen: ${stubgen_path}") - install(CODE "execute_process(COMMAND ${PYTHON_EXEcUTABLE} -m pybind11_stubgen --no-setup-py netgen)") + install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} -m pybind11_stubgen --no-setup-py netgen)") install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../stubs/netgen-stubs/ DESTINATION ${NG_INSTALL_DIR_PYTHON}/netgen/ COMPONENT netgen) endif() endif(BUILD_STUB_FILES) From c0b8b1c0cc177a10dc14b22de2cb818ee692f0f2 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Thu, 23 Jul 2020 20:12:20 +0200 Subject: [PATCH 085/384] Parallel SplitImprove2, update test results Due to prallelization, the order of splits is changed (sort by improvement of badness, like in other optimization passes) --- libsrc/meshing/improve3.cpp | 336 +++++++++++++++++++++++------------- libsrc/meshing/improve3.hpp | 4 +- libsrc/meshing/meshfunc.cpp | 2 +- tests/pytest/results.json | 222 +++++++++++++++++------- 4 files changed, 375 insertions(+), 189 deletions(-) diff --git a/libsrc/meshing/improve3.cpp b/libsrc/meshing/improve3.cpp index 940bc2ed..973afbbd 100644 --- a/libsrc/meshing/improve3.cpp +++ b/libsrc/meshing/improve3.cpp @@ -95,6 +95,51 @@ static ArrayMem SplitElement (Element old, PointIndex pi0, PointInde return new_elements; }; +static double SplitElementBadness (const Mesh::T_POINTS & points, const MeshingParameters & mp, Element old, PointIndex pi0, PointIndex pi1, MeshPoint & pnew) +{ + double badness = 0; + auto np = old.GetNP(); + PointIndex dummy{-1}; + if(np == 4) + { + // Split tet into two tets + badness += CalcBadReplacePoints ( points, mp, old, 0, pi0, dummy, pnew ); + badness += CalcBadReplacePoints ( points, mp, old, 0, pi1, dummy, pnew ); + } + else if (np == 5) + { + // split pyramid into pyramid and two tets + auto pibase = (pi0==old[4]) ? pi1 : pi0; + auto pitop = (pi0==old[4]) ? pi0 : pi1; + + badness += CalcBadReplacePoints ( points, mp, old, 0, pitop, dummy, pnew ); + + Element tet = old; + tet.SetType(TET); + + size_t pibase_index=0; + for(auto i : Range(4)) + if(old[i]==pibase) + pibase_index = i; + + MeshPoint p[4]; + p[0] = points[old[(pibase_index+1)%4]]; + p[1] = points[old[(pibase_index+2)%4]]; + p[2] = pnew; + p[3] = points[pitop]; + badness += CalcTetBadness (p[0], p[1], p[2], p[3], 0, mp); + + p[0] = points[old[(pibase_index+2)%4]]; + p[1] = points[old[(pibase_index+3)%4]]; + p[2] = pnew; + p[3] = points[pitop]; + badness += CalcTetBadness (p[0], p[1], p[2], p[3], 0, mp); + } + + return badness; +}; + + /* Combine two points to one. Set new point into the center, if both are @@ -3970,13 +4015,148 @@ void MeshOptimize3d :: SwapImprove2 (Mesh & mesh, OPTIMIZEGOAL goal) (*testout) << "swapimprove2 done" << "\n"; } +double MeshOptimize3d :: SplitImprove2Element (Mesh & mesh, + ElementIndex ei, + const Table & elements_of_point, + const Array & el_badness, + bool check_only) +{ + auto & el = mesh[ei]; + if(el.GetType() != TET) + return false; + + // Optimize only bad elements + if(el_badness[ei] < 100) + return false; + + // search for very flat tets, with two disjoint edges nearly crossing, like a rectangle with diagonals + static constexpr int tetedges[6][2] = + { { 0, 1 }, { 0, 2 }, { 0, 3 }, + { 1, 2 }, { 1, 3 }, { 2, 3 } }; + + int minedge = -1; + double mindist = 1e99; + double minlam0, minlam1; + + for (int i : Range(3)) + { + auto pi0 = el[tetedges[i][0]]; + auto pi1 = el[tetedges[i][1]]; + auto pi2 = el[tetedges[5-i][0]]; + auto pi3 = el[tetedges[5-i][1]]; + + double lam0, lam1; + double dist = MinDistLL2(mesh[pi0], mesh[pi1], mesh[pi2], mesh[pi3], lam0, lam1 ); + if(dist has_both_points0; + ArrayMem has_both_points1; + + Point3d p[4] = { mesh[el[0]], mesh[el[1]], mesh[el[2]], mesh[el[3]] }; + auto center = Center(p[0]+minlam0*(p[1]-p[0]), p[2]+minlam1*(p[3]-p[2])); + MeshPoint pnew; + + pnew(0) = center.X(); + pnew(1) = center.Y(); + pnew(2) = center.Z(); + + // find all tets with edge (pi0,pi1) or (pi2,pi3) + for (auto ei0 : elements_of_point[pi0] ) + { + Element & elem = mesh[ei0]; + if (elem.IsDeleted()) return false; + if (ei0 == ei) continue; + + if (elem[0] == pi1 || elem[1] == pi1 || elem[2] == pi1 || elem[3] == pi1 || (elem.GetNP()==5 && elem[4]==pi1) ) + if(!has_both_points0.Contains(ei0)) + has_both_points0.Append (ei0); + } + + for (auto ei1 : elements_of_point[pi2] ) + { + Element & elem = mesh[ei1]; + if (elem.IsDeleted()) return false; + if (ei1 == ei) continue; + + if (elem[0] == pi3 || elem[1] == pi3 || elem[2] == pi3 || elem[3] == pi3 || (elem.GetNP()==5 && elem[4]==pi3)) + if(!has_both_points1.Contains(ei1)) + has_both_points1.Append (ei1); + } + + double badness_before = el_badness[ei]; + double badness_after = 0.0; + + for (auto ei0 : has_both_points0) + { + badness_before += el_badness[ei0]; + badness_after += SplitElementBadness (mesh.Points(), mp, mesh[ei0], pi0, pi1, pnew); + } + for (auto ei1 : has_both_points1) + { + badness_before += el_badness[ei1]; + badness_after += SplitElementBadness (mesh.Points(), mp, mesh[ei1], pi2, pi3, pnew); + } + + if(check_only) + return badness_after-badness_before; + + if(badness_after new point where diagonals cross, remove the flat tet -void MeshOptimize3d :: SplitImprove2 (Mesh & mesh, OPTIMIZEGOAL goal) +void MeshOptimize3d :: SplitImprove2 (Mesh & mesh) { - double bad1 = mesh.CalcTotalBad (mp); + static Timer t("MeshOptimize3d::SplitImprove2"); RegionTimer reg(t); + static Timer tsearch("Search"); + static Timer topt("Optimize"); + int ne = mesh.GetNE(); auto elements_of_point = mesh.CreatePoint2ElementTable(); + int ntasks = 4*ngcore::TaskManager::GetNumThreads(); + + const char * savetask = multithread.task; + multithread.task = "Optimize Volume: Split Improve 2"; Array el_badness (ne); @@ -3985,141 +4165,51 @@ void MeshOptimize3d :: SplitImprove2 (Mesh & mesh, OPTIMIZEGOAL goal) for (ElementIndex ei : myrange) { if(mp.only3D_domain_nr && mp.only3D_domain_nr != mesh[ei].GetIndex()) - continue; + continue; el_badness[ei] = CalcBad (mesh.Points(), mesh[ei], 0); } }); mesh.BoundaryEdge (1,2); // ensure the boundary-elements table is built - // TODO: Parallelization - for (ElementIndex ei : Range(ne) ) + Array> split_candidates(ne); + std::atomic improvement_counter(0); + + tsearch.Start(); + ParallelForRange(Range(ne), [&] (auto myrange) { - auto & el = mesh[ei]; - if(el.GetType() != TET) - continue; - - // Optimize only bad elements - if(el_badness[ei] < 100) - continue; - - // search for very flat tets, with two disjoint edges nearly crossing, like a rectangle with diagonals - static constexpr int tetedges[6][2] = - { { 0, 1 }, { 0, 2 }, { 0, 3 }, - { 1, 2 }, { 1, 3 }, { 2, 3 } }; - - int minedge = -1; - double mindist = 1e99; - double minlam0, minlam1; - - for (int i : Range(3)) + for(ElementIndex ei : myrange) { - auto pi0 = el[tetedges[i][0]]; - auto pi1 = el[tetedges[i][1]]; - auto pi2 = el[tetedges[5-i][0]]; - auto pi3 = el[tetedges[5-i][1]]; - - double lam0, lam1; - double dist = MinDistLL2(mesh[pi0], mesh[pi1], mesh[pi2], mesh[pi3], lam0, lam1 ); - if(dist has_both_points0; - ArrayMem has_both_points1; - - Point3d p[4] = { mesh[el[0]], mesh[el[1]], mesh[el[2]], mesh[el[3]] }; - auto center = Center(p[0]+minlam0*(p[1]-p[0]), p[2]+minlam1*(p[3]-p[2])); - MeshPoint pnew; - - pnew(0) = center.X(); - pnew(1) = center.Y(); - pnew(2) = center.Z(); - - bool valid = true; - // find all tets with edge (pi0,pi1) or (pi2,pi3) - for (auto ei0 : elements_of_point[pi0] ) - { - Element & elem = mesh[ei0]; - if (elem.IsDeleted()) valid = false; - if (ei0 == ei) continue; - - if (elem[0] == pi1 || elem[1] == pi1 || elem[2] == pi1 || elem[3] == pi1 || (elem.GetNP()==5 && elem[4]==pi1) ) - if(!has_both_points0.Contains(ei0)) - has_both_points0.Append (ei0); - } - - for (auto ei1 : elements_of_point[pi2] ) - { - Element & elem = mesh[ei1]; - if (elem.IsDeleted()) valid = false; - if (ei1 == ei) continue; - - if (elem[0] == pi3 || elem[1] == pi3 || elem[2] == pi3 || elem[3] == pi3 || (elem.GetNP()==5 && elem[4]==pi3)) - if(!has_both_points1.Contains(ei1)) - has_both_points1.Append (ei1); - } - if(!valid) continue; - double badness_before = el_badness[ei]; - - double badness_after = 0.0; - PointIndex dummy{-1}; - - PointIndex pinew = mesh.AddPoint (center); - for (auto ei0 : has_both_points0) - { - badness_before += el_badness[ei0]; - auto new_els = SplitElement(mesh[ei0], pi0, pi1, pinew); - for(const auto & el : new_els) - badness_after += CalcBad (mesh.Points(), el, 0); - } - for (auto ei1 : has_both_points1) - { - badness_before += el_badness[ei1]; - auto new_els = SplitElement(mesh[ei1], pi2, pi3, pinew); - for(const auto & el : new_els) - badness_after += CalcBad (mesh.Points(), el, 0); - } - if(badness_after0) + mesh.Compress(); + multithread.task = savetask; } diff --git a/libsrc/meshing/improve3.hpp b/libsrc/meshing/improve3.hpp index 19246a52..b850fe55 100644 --- a/libsrc/meshing/improve3.hpp +++ b/libsrc/meshing/improve3.hpp @@ -39,7 +39,9 @@ public: void SplitImprove (Mesh & mesh, OPTIMIZEGOAL goal = OPT_QUALITY); void SplitImproveSequential (Mesh & mesh, OPTIMIZEGOAL goal = OPT_QUALITY); double SplitImproveEdge (Mesh & mesh, OPTIMIZEGOAL goal, Table & elementsonnode, Array &elerrs, NgArray &locfaces, double badmax, PointIndex pi1, PointIndex pi2, PointIndex ptmp, bool check_only=false); - void SplitImprove2 (Mesh & mesh, OPTIMIZEGOAL goal); + + void SplitImprove2 (Mesh & mesh); + double SplitImprove2Element (Mesh & mesh, ElementIndex ei, const Table & elements_of_point, const Array & elerrs, bool check_only); double SwapImproveEdge (Mesh & mesh, OPTIMIZEGOAL goal, const NgBitArray * working_elements, Table & elementsonnode, INDEX_3_HASHTABLE & faces, PointIndex pi1, PointIndex pi2, bool check_only=false); diff --git a/libsrc/meshing/meshfunc.cpp b/libsrc/meshing/meshfunc.cpp index 4221440c..f3ebccde 100644 --- a/libsrc/meshing/meshfunc.cpp +++ b/libsrc/meshing/meshfunc.cpp @@ -684,7 +684,7 @@ namespace netgen { case 'c': optmesh.CombineImprove(mesh3d, OPT_REST); break; case 'd': optmesh.SplitImprove(mesh3d); break; - case 'D': optmesh.SplitImprove2(mesh3d, OPT_QUALITY); break; + case 'D': optmesh.SplitImprove2(mesh3d); break; case 's': optmesh.SwapImprove(mesh3d); break; // case 'u': optmesh.SwapImproveSurface(mesh3d); break; case 't': optmesh.SwapImprove2(mesh3d); break; diff --git a/tests/pytest/results.json b/tests/pytest/results.json index 6898733e..b2845af1 100644 --- a/tests/pytest/results.json +++ b/tests/pytest/results.json @@ -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.9281305 + "total_badness": 4176.9278168 }, { "angles_tet": [ @@ -1176,8 +1176,8 @@ "ne1d": 432, "ne2d": 9544, "ne3d": 69846, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 1, 7, 30, 71, 221, 652, 1560, 3667, 7029, 11233, 14630, 15524, 11810, 3411]", - "total_badness": 85625.273734 + "quality_histogram": "[0, 0, 0, 0, 0, 0, 1, 7, 30, 71, 221, 652, 1560, 3667, 7028, 11234, 14630, 15524, 11810, 3411]", + "total_badness": 85625.275421 } ], "ellipticcyl.geo": [ @@ -1364,6 +1364,53 @@ "total_badness": 639.78974791 } ], + "frame.step": [ + { + "angles_tet": [ + 2.9095, + 171.1 + ], + "angles_trig": [ + 2.6092, + 172.05 + ], + "ne1d": 10108, + "ne2d": 30160, + "ne3d": 153012, + "quality_histogram": "[0, 3, 1, 3, 6, 20, 57, 149, 536, 1257, 2919, 5836, 10439, 16388, 21788, 26067, 26565, 22916, 14350, 3712]", + "total_badness": 202656.25887 + }, + { + "angles_tet": [ + 2.296, + 175.61 + ], + "angles_trig": [ + 1.8443, + 175.57 + ], + "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 + }, + { + "angles_tet": [ + 2.5792, + 174.11 + ], + "angles_trig": [ + 2.2053, + 174.13 + ], + "ne1d": 9622, + "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 + } + ], "hinge.stl": [ { "angles_tet": [ @@ -1652,9 +1699,9 @@ ], "ne1d": 5886, "ne2d": 48052, - "ne3d": 178832, - "quality_histogram": "[0, 0, 0, 0, 0, 5, 11, 72, 289, 828, 2308, 6210, 10937, 18854, 27390, 30600, 31363, 26926, 18496, 4543]", - "total_badness": 233895.88826 + "ne3d": 178844, + "quality_histogram": "[0, 0, 0, 0, 0, 5, 11, 71, 288, 829, 2312, 6198, 10948, 18856, 27414, 30640, 31333, 26927, 18474, 4538]", + "total_badness": 233920.54177 }, { "angles_tet": [ @@ -1722,8 +1769,8 @@ }, { "angles_tet": [ - 7.9601, - 167.83 + 9.3063, + 165.3 ], "angles_trig": [ 7.9174, @@ -1731,9 +1778,9 @@ ], "ne1d": 106, "ne2d": 610, - "ne3d": 1658, - "quality_histogram": "[0, 1, 14, 48, 79, 156, 193, 158, 156, 122, 138, 142, 136, 108, 66, 40, 31, 41, 25, 4]", - "total_badness": 4098.9846426 + "ne3d": 1659, + "quality_histogram": "[0, 1, 13, 49, 81, 155, 190, 149, 159, 132, 135, 145, 137, 107, 66, 37, 33, 40, 26, 4]", + "total_badness": 4094.4605262 }, { "angles_tet": [ @@ -1783,7 +1830,7 @@ { "angles_tet": [ 18.203, - 145.26 + 145.38 ], "angles_trig": [ 17.821, @@ -1791,9 +1838,9 @@ ], "ne1d": 418, "ne2d": 5968, - "ne3d": 101104, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 4, 7, 52, 103, 348, 992, 2548, 5550, 10212, 16062, 20713, 22250, 16917, 5346]", - "total_badness": 124141.43144 + "ne3d": 101113, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 4, 7, 51, 102, 349, 993, 2550, 5563, 10196, 16090, 20698, 22258, 16911, 5341]", + "total_badness": 124155.81178 } ], "ortho.geo": [ @@ -2144,9 +2191,9 @@ ], "ne1d": 2992, "ne2d": 23322, - "ne3d": 281901, - "quality_histogram": "[4, 10, 12, 10, 9, 21, 29, 61, 95, 247, 747, 2145, 5539, 13549, 27678, 44557, 59948, 64037, 48291, 14912]", - "total_badness": 344516.23097 + "ne3d": 281896, + "quality_histogram": "[4, 10, 12, 10, 9, 21, 29, 61, 95, 246, 747, 2146, 5540, 13546, 27675, 44558, 59947, 64037, 48291, 14912]", + "total_badness": 344508.9779 } ], "revolution.geo": [ @@ -2241,6 +2288,53 @@ "total_badness": 244286.77424 } ], + "screw.step": [ + { + "angles_tet": [ + 15.139, + 148.36 + ], + "angles_trig": [ + 17.363, + 140.59 + ], + "ne1d": 400, + "ne2d": 1436, + "ne3d": 2342, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 16, 61, 92, 165, 209, 246, 307, 280, 262, 272, 182, 148, 84, 18]", + "total_badness": 3718.1755695 + }, + { + "angles_tet": [ + 21.55, + 146.38 + ], + "angles_trig": [ + 17.221, + 126.09 + ], + "ne1d": 528, + "ne2d": 2792, + "ne3d": 8129, + "quality_histogram": "[0, 0, 0, 0, 0, 1, 4, 8, 35, 96, 188, 298, 537, 817, 1057, 1323, 1446, 1284, 798, 237]", + "total_badness": 10753.086327 + }, + { + "angles_tet": [ + 20.515, + 144.03 + ], + "angles_trig": [ + 24.891, + 120.48 + ], + "ne1d": 666, + "ne2d": 4922, + "ne3d": 31540, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 1, 5, 31, 92, 290, 707, 1762, 3221, 4997, 6712, 6966, 5146, 1610]", + "total_badness": 38689.280913 + } + ], "sculpture.geo": [ { "angles_tet": [ @@ -2914,7 +3008,7 @@ "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.68014 + "total_badness": 13234.755766 }, { "angles_tet": [ @@ -2985,13 +3079,13 @@ ], "angles_trig": [ 14.916, - 130.79 + 132.02 ], "ne1d": 690, "ne2d": 1684, - "ne3d": 5186, - "quality_histogram": "[0, 0, 1, 0, 0, 9, 26, 34, 106, 192, 291, 357, 463, 570, 662, 695, 628, 542, 471, 139]", - "total_badness": 7461.9914431 + "ne3d": 5177, + "quality_histogram": "[0, 0, 1, 0, 1, 8, 27, 37, 108, 191, 285, 369, 461, 565, 670, 690, 621, 536, 462, 145]", + "total_badness": 7461.1502455 }, { "angles_tet": [ @@ -3019,9 +3113,9 @@ ], "ne1d": 512, "ne2d": 874, - "ne3d": 2382, - "quality_histogram": "[0, 0, 0, 3, 9, 13, 41, 68, 124, 140, 196, 215, 305, 390, 343, 237, 128, 98, 47, 25]", - "total_badness": 3929.8055104 + "ne3d": 2381, + "quality_histogram": "[0, 0, 0, 3, 9, 13, 41, 68, 124, 140, 196, 214, 302, 390, 345, 237, 128, 98, 47, 26]", + "total_badness": 3927.0434195 }, { "angles_tet": [ @@ -3030,13 +3124,13 @@ ], "angles_trig": [ 14.916, - 130.79 + 132.02 ], "ne1d": 690, "ne2d": 1684, - "ne3d": 5110, - "quality_histogram": "[0, 0, 1, 0, 0, 4, 18, 33, 104, 176, 266, 350, 443, 555, 682, 703, 613, 551, 468, 143]", - "total_badness": 7297.2366495 + "ne3d": 5095, + "quality_histogram": "[0, 0, 1, 0, 0, 4, 19, 34, 101, 181, 263, 354, 439, 548, 689, 696, 611, 547, 467, 141]", + "total_badness": 7282.7477612 }, { "angles_tet": [ @@ -3049,9 +3143,9 @@ ], "ne1d": 1050, "ne2d": 3812, - "ne3d": 18010, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 3, 15, 34, 61, 181, 572, 1425, 2192, 2302, 2698, 2704, 2739, 2390, 694]", - "total_badness": 23478.48161 + "ne3d": 18003, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 3, 15, 34, 61, 181, 573, 1428, 2189, 2298, 2700, 2707, 2735, 2389, 690]", + "total_badness": 23471.146878 }, { "angles_tet": [ @@ -3064,26 +3158,26 @@ ], "ne1d": 1722, "ne2d": 10042, - "ne3d": 84793, - "quality_histogram": "[0, 0, 0, 0, 0, 2, 50, 1428, 718, 373, 701, 1171, 2465, 5462, 8878, 13214, 16426, 16935, 12864, 4106]", - "total_badness": 108481.65242 + "ne3d": 84812, + "quality_histogram": "[0, 0, 0, 0, 0, 2, 49, 1423, 720, 374, 704, 1174, 2454, 5477, 8890, 13211, 16429, 16935, 12870, 4100]", + "total_badness": 108503.84867 } ], "twobricks.geo": [ { "angles_tet": [ - 25.655, - 137.37 + 29.453, + 134.56 ], "angles_trig": [ - 23.972, - 121.23 + 26.574, + 91.538 ], "ne1d": 72, "ne2d": 50, - "ne3d": 43, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 5, 6, 3, 16, 3, 6, 1, 1, 0, 0]", - "total_badness": 67.089294311 + "ne3d": 36, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 8, 2, 18, 2, 4, 0, 0, 0, 0]", + "total_badness": 55.618194358 }, { "angles_tet": [ @@ -3117,18 +3211,18 @@ }, { "angles_tet": [ - 25.655, - 137.37 + 29.453, + 134.56 ], "angles_trig": [ - 23.971, - 121.23 + 26.574, + 91.538 ], "ne1d": 72, "ne2d": 50, - "ne3d": 43, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 5, 6, 3, 16, 3, 6, 1, 1, 0, 0]", - "total_badness": 67.089294246 + "ne3d": 36, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 8, 2, 18, 2, 4, 0, 0, 0, 0]", + "total_badness": 55.618194358 }, { "angles_tet": [ @@ -3164,18 +3258,18 @@ "twocubes.geo": [ { "angles_tet": [ - 25.655, - 137.37 + 29.453, + 134.56 ], "angles_trig": [ - 23.972, - 121.23 + 26.574, + 91.538 ], "ne1d": 72, "ne2d": 50, - "ne3d": 43, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 5, 6, 3, 16, 3, 6, 1, 1, 0, 0]", - "total_badness": 67.089294311 + "ne3d": 36, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 8, 2, 18, 2, 4, 0, 0, 0, 0]", + "total_badness": 55.618194358 }, { "angles_tet": [ @@ -3209,18 +3303,18 @@ }, { "angles_tet": [ - 25.655, - 137.37 + 29.453, + 134.56 ], "angles_trig": [ - 23.971, - 121.23 + 26.574, + 91.538 ], "ne1d": 72, "ne2d": 50, - "ne3d": 43, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 5, 6, 3, 16, 3, 6, 1, 1, 0, 0]", - "total_badness": 67.089294246 + "ne3d": 36, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 8, 2, 18, 2, 4, 0, 0, 0, 0]", + "total_badness": 55.618194358 }, { "angles_tet": [ From ae268637cfe6a0dd4d6e44585259744fe5097b1f Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Mon, 27 Jul 2020 18:06:43 +0200 Subject: [PATCH 086/384] revert pyramid-specific code in optimizations --- libsrc/meshing/improve3.cpp | 28 ++++++++++----------------- libsrc/meshing/improve3.hpp | 29 ++++++++++++++-------------- libsrc/meshing/smoothing3.cpp | 36 +++++------------------------------ 3 files changed, 30 insertions(+), 63 deletions(-) diff --git a/libsrc/meshing/improve3.cpp b/libsrc/meshing/improve3.cpp index 973afbbd..3ddc0733 100644 --- a/libsrc/meshing/improve3.cpp +++ b/libsrc/meshing/improve3.cpp @@ -16,28 +16,16 @@ namespace netgen // Calc badness of new element where pi1 and pi2 are replaced by pnew -static double CalcBadReplacePoints (const Mesh::T_POINTS & points, const MeshingParameters & mp, const Element & elem, double h, PointIndex &pi1, PointIndex &pi2, MeshPoint &pnew) +double CalcBadReplacePoints (const Mesh::T_POINTS & points, const MeshingParameters & mp, const Element & elem, double h, PointIndex &pi1, PointIndex &pi2, MeshPoint &pnew) { - if (elem.GetType() != TET && elem.GetType() != PYRAMID) - return 0; + if (elem.GetType() != TET) return 0; - MeshPoint p[5]; + MeshPoint* p[] = {&points[elem[0]], &points[elem[1]], &points[elem[2]], &points[elem[3]]}; - for (auto i : Range(elem.GetNP())) - { - auto pi = elem[i]; - if(pi==pi1 || pi==pi2) - p[i] = pnew; - else - p[i] = points[pi]; - } + for (auto i : Range(4)) + if(elem[i]==pi1 || elem[i]==pi2) p[i] = &pnew; - if (elem.GetType() == TET) - return CalcTetBadness (p[0], p[1], p[2], p[3], h, mp); - if (elem.GetType() == PYRAMID) - return CalcTetBadness (p[0], p[1], p[2], p[4], h, mp) - + CalcTetBadness (p[2], p[3], p[0], p[4], h, mp); - return 0; + return CalcTetBadness (*p[0], *p[1], *p[2], *p[3], h, mp); } static ArrayMem SplitElement (Element old, PointIndex pi0, PointIndex pi1, PointIndex pinew) @@ -4107,11 +4095,15 @@ double MeshOptimize3d :: SplitImprove2Element (Mesh & mesh, for (auto ei0 : has_both_points0) { + if(mesh[ei0].GetType()!=TET) + return false; badness_before += el_badness[ei0]; badness_after += SplitElementBadness (mesh.Points(), mp, mesh[ei0], pi0, pi1, pnew); } for (auto ei1 : has_both_points1) { + if(mesh[ei1].GetType()!=TET) + return false; badness_before += el_badness[ei1]; badness_after += SplitElementBadness (mesh.Points(), mp, mesh[ei1], pi2, pi3, pnew); } diff --git a/libsrc/meshing/improve3.hpp b/libsrc/meshing/improve3.hpp index b850fe55..b518a910 100644 --- a/libsrc/meshing/improve3.hpp +++ b/libsrc/meshing/improve3.hpp @@ -1,19 +1,6 @@ #ifndef FILE_IMPROVE3 #define FILE_IMPROVE3 -inline double -CalcBad (const Mesh::T_POINTS & points, const Element & elem, double h, const MeshingParameters & mp) -{ - if (elem.GetType() == TET) - return CalcTetBadness (points[elem[0]], points[elem[1]], - points[elem[2]], points[elem[3]], h, mp); - if (elem.GetType() == PYRAMID) - return CalcTetBadness (points[elem[0]], points[elem[1]], - points[elem[2]], points[elem[4]], h, mp) - + CalcTetBadness (points[elem[2]], points[elem[3]], - points[elem[0]], points[elem[4]], h, mp); - return 0; -} extern double CalcTotalBad (const Mesh::T_POINTS & points, const Array & elements, @@ -59,9 +46,13 @@ public: double CalcBad (const Mesh::T_POINTS & points, const Element & elem, double h) { - return ::netgen::CalcBad(points, elem, h, mp); + if (elem.GetType() == TET) + return CalcTetBadness (points[elem[0]], points[elem[1]], + points[elem[2]], points[elem[3]], h, mp); + return 0; } + double CalcTotalBad (const Mesh::T_POINTS & points, const Array & elements) { @@ -71,6 +62,16 @@ public: }; +inline double +CalcBad (const Mesh::T_POINTS & points, const Element & elem, double h, const MeshingParameters & mp) +{ + if (elem.GetType() == TET) + return CalcTetBadness (points[elem[0]], points[elem[1]], + points[elem[2]], points[elem[3]], h, mp); + return 0; +} + + extern int WrongOrientation (const Mesh::T_POINTS & points, const Element & el); diff --git a/libsrc/meshing/smoothing3.cpp b/libsrc/meshing/smoothing3.cpp index e53bf510..e84a18ba 100644 --- a/libsrc/meshing/smoothing3.cpp +++ b/libsrc/meshing/smoothing3.cpp @@ -339,9 +339,9 @@ namespace netgen { static Timer tim("PointFunction - build elementsonpoint table"); RegionTimer reg(tim); for (int i = 0; i < elements.Size(); i++) - if (!elements[i].IsDeleted()) - for (int j = 0; j < elements[i].GetNP(); j++) - elementsonpoint.Add (elements[i][j], i); + if (elements[i].NP() == 4) + for (int j = 0; j < elements[i].NP(); j++) + elementsonpoint.Add (elements[i][j], i); } void PointFunction :: SetPointIndex (PointIndex aactpind) @@ -362,7 +362,8 @@ namespace netgen for (int j = 0; j < elementsonpoint[actpind].Size(); j++) { const Element & el = elements[elementsonpoint[actpind][j]]; - badness += CalcBad(points, el, -1, mp); + badness += CalcTetBadness (points[el[0]], points[el[1]], + points[el[2]], points[el[3]], -1, mp); } points[actpind] = Point<3> (hp); @@ -390,19 +391,6 @@ namespace netgen vgrad += vgradi; } - if(el.GetType()==PYRAMID) - { - f += CalcTetBadnessGrad (points[el[0]], - points[el[1]], - points[el[2]], - points[el[4]], -1, 4, vgradi, mp); - vgrad += vgradi; - f += CalcTetBadnessGrad (points[el[2]], - points[el[3]], - points[el[0]], - points[el[4]], -1, 4, vgradi, mp); - vgrad += vgradi; - } } points[actpind] = Point<3> (hp); @@ -435,20 +423,6 @@ namespace netgen vgrad += vgradi; } - - if(el.GetType()==PYRAMID) - { - f += CalcTetBadnessGrad (points[el[0]], - points[el[1]], - points[el[2]], - points[el[4]], -1, 4, vgradi, mp); - vgrad += vgradi; - f += CalcTetBadnessGrad (points[el[2]], - points[el[3]], - points[el[0]], - points[el[4]], -1, 4, vgradi, mp); - vgrad += vgradi; - } } points[actpind] = Point<3> (hp); From eb75bc31a64022be9eed9306146684ad81ad7aa5 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Wed, 29 Jul 2020 17:18:12 +0200 Subject: [PATCH 087/384] mpi4py support --- CMakeLists.txt | 9 +++++ libsrc/meshing/python_mesh.cpp | 63 ++++++++++++++++++++++++++++++++++ tests/dockerfile_mpi | 2 +- 3 files changed, 73 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d6197b45..5a003954 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,6 +14,7 @@ option( USE_NATIVE_ARCH "build for native cpu architecture" ON) option( USE_GUI "don't build netgen with GUI" ON ) option( USE_PYTHON "build with python interface" ON ) option( USE_MPI "enable mpi parallelization" OFF ) +option( USE_MPI4PY "enable mpi4py interface" ON ) option( USE_OCC "(not supported) compile with OpenCascade geometry kernel" OFF) option( USE_JPEG "enable snapshots using library libjpeg" OFF ) option( USE_MPEG "enable video recording with FFmpeg, uses libavcodec" OFF ) @@ -297,6 +298,14 @@ if (USE_MPI) target_include_directories(netgen_metis INTERFACE ${METIS_INCLUDE_DIR}) target_link_libraries(netgen_metis INTERFACE ${METIS_LIBRARY} ) target_compile_definitions(netgen_metis INTERFACE METIS ) + + if(USE_MPI4PY AND USE_PYTHON) + execute_process(COMMAND ${PYTHON_EXECUTABLE} -c "import mpi4py;print(mpi4py.get_include())" OUTPUT_VARIABLE mpi4py_path OUTPUT_STRIP_TRAILING_WHITESPACE) + find_path(MPI4PY_INCLUDE_DIR mpi4py.h HINTS ${mpi4py_path}/mpi4py NO_DEFAULT_PATH REQUIRED) + target_include_directories(netgen_metis INTERFACE ${MPI4PY_INCLUDE_DIR}) + target_compile_definitions(netgen_metis INTERFACE NG_MPI4PY ) + message(STATUS "Found mpi4py: ${MPI4PY_INCLUDE_DIR}") + endif(USE_MPI4PY AND USE_PYTHON) endif (USE_MPI) install(TARGETS netgen_mpi netgen_metis ${NG_INSTALL_DIR}) diff --git a/libsrc/meshing/python_mesh.cpp b/libsrc/meshing/python_mesh.cpp index d2d57f89..47dc99c6 100644 --- a/libsrc/meshing/python_mesh.cpp +++ b/libsrc/meshing/python_mesh.cpp @@ -13,6 +13,53 @@ #include <../interface/writeuser.hpp> +#ifdef NG_MPI4PY +#include + +struct mpi4py_comm { + mpi4py_comm() = default; + mpi4py_comm(MPI_Comm value) : value(value) {} + operator MPI_Comm () { return value; } + + MPI_Comm value; +}; + +namespace pybind11 { namespace detail { + template <> struct type_caster { + public: + PYBIND11_TYPE_CASTER(mpi4py_comm, _("mpi4py_comm")); + + // Python -> C++ + bool load(handle src, bool) { + PyObject *py_src = src.ptr(); + // Check that we have been passed an mpi4py communicator + if (PyObject_TypeCheck(py_src, &PyMPIComm_Type)) { + // Convert to regular MPI communicator + value.value = *PyMPIComm_Get(py_src); + } else { + return false; + } + + return !PyErr_Occurred(); + } + + // C++ -> Python + static handle cast(mpi4py_comm src, + return_value_policy /* policy */, + handle /* parent */) + { + // Create an mpi4py handle + return PyMPIComm_New(src.value); + } + }; +}} // namespace pybind11::detail + +#endif // NG_MPI4PY + + + + + using namespace netgen; extern const char *ngscript[]; @@ -50,8 +97,15 @@ void TranslateException (const NgException & ex) static Transformation<3> global_trafo(Vec<3> (0,0,0)); + + + + DLL_HEADER void ExportNetgenMeshing(py::module &m) { +#ifdef NG_MPI4PY + import_mpi4py(); +#endif // NG_MPI4PY py::register_exception(m, "NgException"); m.attr("_netgen_executable_started") = py::cast(netgen::netgen_executable_started); string script; @@ -71,6 +125,12 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m) m.def("_SetThreadPercentage", [](double percent) { SetThreadPercent(percent); }); py::class_ (m, "MPI_Comm") +#ifdef NG_MPI4PY + .def(py::init([] (mpi4py_comm comm) + { + return NgMPI_Comm(comm); + })) +#endif // NG_MPI4PY .def_property_readonly ("rank", &NgMPI_Comm::Rank) .def_property_readonly ("size", &NgMPI_Comm::Size) .def("Barrier", &NgMPI_Comm::Barrier) @@ -100,6 +160,9 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m) ; +#ifdef NG_MPI4PY + py::implicitly_convertible(); +#endif // NG_MPI4PY py::class_(m, "NGDummyArgument") diff --git a/tests/dockerfile_mpi b/tests/dockerfile_mpi index ddb7e51b..7735bf23 100644 --- a/tests/dockerfile_mpi +++ b/tests/dockerfile_mpi @@ -1,5 +1,5 @@ FROM ubuntu:18.04 ENV DEBIAN_FRONTEND=noninteractive MAINTAINER Matthias Hochsteger -RUN apt-get update && apt-get -y install python3 libpython3-dev libxmu-dev tk-dev tcl-dev cmake git g++ libglu1-mesa-dev ccache python3-pytest python3-numpy python3-tk clang-tidy python3-distutils clang libopenmpi-dev openmpi-bin gfortran +RUN apt-get update && apt-get -y install python3 libpython3-dev libxmu-dev tk-dev tcl-dev cmake git g++ libglu1-mesa-dev ccache python3-pytest python3-numpy python3-tk python3-mpi4py clang-tidy python3-distutils clang libopenmpi-dev openmpi-bin gfortran ADD . /root/src/netgen From 2290d9fe7267b1695c28ba286f88a7bb61201e6f Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Wed, 29 Jul 2020 17:52:21 +0200 Subject: [PATCH 088/384] mpi4py test --- tests/dockerfile_mpi | 3 ++- tests/pytest/CMakeLists.txt | 3 +++ tests/pytest/test_mpi4py.py | 21 +++++++++++++++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 tests/pytest/test_mpi4py.py diff --git a/tests/dockerfile_mpi b/tests/dockerfile_mpi index 7735bf23..5b093937 100644 --- a/tests/dockerfile_mpi +++ b/tests/dockerfile_mpi @@ -1,5 +1,6 @@ FROM ubuntu:18.04 ENV DEBIAN_FRONTEND=noninteractive MAINTAINER Matthias Hochsteger -RUN apt-get update && apt-get -y install python3 libpython3-dev libxmu-dev tk-dev tcl-dev cmake git g++ libglu1-mesa-dev ccache python3-pytest python3-numpy python3-tk python3-mpi4py clang-tidy python3-distutils clang libopenmpi-dev openmpi-bin gfortran +RUN apt-get update && apt-get -y install python3 libpython3-dev python3-pip libxmu-dev tk-dev tcl-dev cmake git g++ libglu1-mesa-dev ccache python3-pytest python3-numpy python3-tk python3-mpi4py clang-tidy python3-distutils clang libopenmpi-dev openmpi-bin gfortran +RUN python3 -m pip install pytest-mpi ADD . /root/src/netgen diff --git a/tests/pytest/CMakeLists.txt b/tests/pytest/CMakeLists.txt index bc6b8b26..26c7d22f 100644 --- a/tests/pytest/CMakeLists.txt +++ b/tests/pytest/CMakeLists.txt @@ -2,4 +2,7 @@ if(USE_PYTHON) add_test(NAME pytest COMMAND ${PYTHON_EXECUTABLE} -m pytest WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) add_custom_target(pytest ${PYTHON_EXECUTABLE} -m pytest WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) set_tests_properties ( pytest PROPERTIES TIMEOUT 1800 ) + if(USE_MPI AND USE_MPI4PY) + add_test(NAME pytest-mpi COMMAND ${MPIEXEC_EXECUTABLE} --allow-run-as-root -np 4 ${PYTHON_EXECUTABLE} -m pytest --with-mpi test_mpi4py.py WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) + endif(USE_MPI AND USE_MPI4PY) endif(USE_PYTHON) diff --git a/tests/pytest/test_mpi4py.py b/tests/pytest/test_mpi4py.py new file mode 100644 index 00000000..b4c85902 --- /dev/null +++ b/tests/pytest/test_mpi4py.py @@ -0,0 +1,21 @@ +import pytest +import netgen.meshing + +mpi4py = pytest.importorskip("mpi4py") + +@pytest.mark.mpi +def test_mpi4py(): + comm = mpi4py.MPI.COMM_WORLD + + if comm.rank==0: + from netgen.csg import unit_cube + m = unit_cube.GenerateMesh(maxh=0.1) + m.Save("mpimesh") + + comm.Barrier() + + mesh = netgen.meshing.Mesh(3, comm) + mesh.Load("mpimesh.vol.gz") + + if comm.rank==0: + assert mesh.ne==0 From c5795aade82e4ceece23d02ecea2c3c7f1b0ea0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20Sch=C3=B6berl?= Date: Thu, 30 Jul 2020 12:31:12 +0200 Subject: [PATCH 089/384] too much printing in parallel refinement --- libsrc/meshing/refine.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libsrc/meshing/refine.cpp b/libsrc/meshing/refine.cpp index 228ebf2b..bc4a2e5b 100644 --- a/libsrc/meshing/refine.cpp +++ b/libsrc/meshing/refine.cpp @@ -13,7 +13,8 @@ namespace netgen void Refinement :: Refine (Mesh & mesh) { - PrintMessage (3, "Refine mesh"); + if (mesh.GetCommunicator().Rank()==0) + PrintMessage (3, "Refine mesh"); mesh.SetNextMajorTimeStamp(); From c074e0c752c60271a12387e976a312181dae16f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20Sch=C3=B6berl?= Date: Fri, 31 Jul 2020 09:57:19 +0200 Subject: [PATCH 090/384] reduce duplicated mpi-wrapping --- libsrc/core/mpi_wrapper.hpp | 8 ++ libsrc/core/ngcore.hpp | 2 +- libsrc/general/mpi_interface.hpp | 235 ++++++------------------------- libsrc/general/ngarray.hpp | 6 + libsrc/gprim/geomobjects.hpp | 2 +- libsrc/meshing/meshtype.cpp | 8 +- libsrc/meshing/parallelmesh.cpp | 8 +- libsrc/meshing/paralleltop.cpp | 121 ---------------- libsrc/meshing/python_mesh.cpp | 35 ++--- 9 files changed, 80 insertions(+), 345 deletions(-) diff --git a/libsrc/core/mpi_wrapper.hpp b/libsrc/core/mpi_wrapper.hpp index c1fc47dd..11af5f04 100644 --- a/libsrc/core/mpi_wrapper.hpp +++ b/libsrc/core/mpi_wrapper.hpp @@ -227,6 +227,14 @@ namespace ngcore MPI_Bcast (&s[0], len, MPI_CHAR, root, comm); } + template + void AllToAll (FlatArray send, FlatArray recv) const + { + MPI_Alltoall (send.Data(), 1, GetMPIType(), + recv.Data(), 1, GetMPIType(), comm); + } + + NgMPI_Comm SubCommunicator (FlatArray procs) const { MPI_Comm subcomm; diff --git a/libsrc/core/ngcore.hpp b/libsrc/core/ngcore.hpp index 91d65bde..72ebde25 100644 --- a/libsrc/core/ngcore.hpp +++ b/libsrc/core/ngcore.hpp @@ -6,6 +6,7 @@ #include "bitarray.hpp" #include "exception.hpp" #include "flags.hpp" +#include "table.hpp" #include "hashtable.hpp" #include "localheap.hpp" #include "logging.hpp" @@ -13,7 +14,6 @@ #include "profiler.hpp" #include "signal.hpp" #include "symboltable.hpp" -#include "table.hpp" #include "taskmanager.hpp" #include "version.hpp" #include "xbool.hpp" diff --git a/libsrc/general/mpi_interface.hpp b/libsrc/general/mpi_interface.hpp index b7de6d64..08e7e85a 100644 --- a/libsrc/general/mpi_interface.hpp +++ b/libsrc/general/mpi_interface.hpp @@ -14,65 +14,8 @@ namespace netgen { - // using ngcore::id; - // using ngcore::ntasks; - -#ifndef PARALLEL - /** without MPI, we need a dummy typedef **/ - // typedef int MPI_Comm; -#endif - - /** This is the "standard" communicator that will be used for netgen-objects. **/ - // extern DLL_HEADER NgMPI_Comm ng_comm; #ifdef OLD -#ifdef PARALLEL - inline int MyMPI_GetNTasks (MPI_Comm comm /* = ng_comm */) - { - int ntasks; - MPI_Comm_size(comm, &ntasks); - return ntasks; - } - inline int MyMPI_GetId (MPI_Comm comm /* = ng_comm */) - { - int id; - MPI_Comm_rank(comm, &id); - return id; - } -#else - // enum { MPI_COMM_WORLD = 12345, MPI_COMM_NULL = 0}; - inline int MyMPI_GetNTasks (MPI_Comm comm /* = ng_comm */) { return 1; } - inline int MyMPI_GetId (MPI_Comm comm /* = ng_comm */) { return 0; } -#endif -#endif - - /* -#ifdef PARALLEL - // For python wrapping of communicators - struct PyMPI_Comm { - MPI_Comm comm; - bool owns_comm; - PyMPI_Comm (MPI_Comm _comm, bool _owns_comm = false) : comm(_comm), owns_comm(_owns_comm) { } - PyMPI_Comm (const PyMPI_Comm & c) = delete; - ~PyMPI_Comm () { - if (owns_comm) - MPI_Comm_free(&comm); - } - inline int Rank() const { return MyMPI_GetId(comm); } - inline int Size() const { return MyMPI_GetNTasks(comm); } - }; -#else - // dummy without MPI - struct PyMPI_Comm { - MPI_Comm comm = 0; - PyMPI_Comm (MPI_Comm _comm, bool _owns_comm = false) { } - ~PyMPI_Comm () { } - inline int Rank() const { return 0; } - inline int Size() const { return 1; } - }; -#endif - */ - #ifdef PARALLEL template inline MPI_Datatype MyGetMPIType ( ) @@ -93,32 +36,35 @@ namespace netgen typedef int MPI_Datatype; template inline MPI_Datatype MyGetMPIType ( ) { return 0; } #endif +#endif + #ifdef PARALLEL enum { MPI_TAG_CMD = 110 }; enum { MPI_TAG_MESH = 210 }; enum { MPI_TAG_VIS = 310 }; - inline void MyMPI_Send (int i, int dest, int tag, MPI_Comm comm /* = ng_comm */) + + [[deprecated("mympi_send int, use comm.Send instead")]] + inline void MyMPI_Send (int i, int dest, int tag, MPI_Comm comm) { int hi = i; MPI_Send( &hi, 1, MPI_INT, dest, tag, comm); } - - inline void MyMPI_Recv (int & i, int src, int tag, MPI_Comm comm /* = ng_comm */) + + [[deprecated("mympi_revc int, use comm.Recv instead")]] + inline void MyMPI_Recv (int & i, int src, int tag, MPI_Comm comm) { MPI_Status status; MPI_Recv( &i, 1, MPI_INT, src, tag, comm, &status); } - - - inline void MyMPI_Send (const string & s, int dest, int tag, MPI_Comm comm /* = ng_comm */) + inline void MyMPI_Send (const string & s, int dest, int tag, MPI_Comm comm) { MPI_Send( const_cast (s.c_str()), s.length(), MPI_CHAR, dest, tag, comm); } - inline void MyMPI_Recv (string & s, int src, int tag, MPI_Comm comm /* = ng_comm */) + inline void MyMPI_Recv (string & s, int src, int tag, MPI_Comm comm) { MPI_Status status; int len; @@ -132,32 +78,32 @@ namespace netgen template - inline void MyMPI_Send (NgFlatArray s, int dest, int tag, MPI_Comm comm /* = ng_comm */) + inline void MyMPI_Send (NgFlatArray s, int dest, int tag, MPI_Comm comm) { - MPI_Send( &s.First(), s.Size(), MyGetMPIType(), dest, tag, comm); + MPI_Send( &s.First(), s.Size(), GetMPIType(), dest, tag, comm); } template - inline void MyMPI_Recv ( NgFlatArray s, int src, int tag, MPI_Comm comm /* = ng_comm */) + inline void MyMPI_Recv ( NgFlatArray s, int src, int tag, MPI_Comm comm) { MPI_Status status; - MPI_Recv( &s.First(), s.Size(), MyGetMPIType(), src, tag, comm, &status); + MPI_Recv( &s.First(), s.Size(), GetMPIType(), src, tag, comm, &status); } template - inline void MyMPI_Recv ( NgArray & s, int src, int tag, MPI_Comm comm /* = ng_comm */) + inline void MyMPI_Recv ( NgArray & s, int src, int tag, MPI_Comm comm) { MPI_Status status; int len; MPI_Probe (src, tag, comm, &status); - MPI_Get_count (&status, MyGetMPIType(), &len); + MPI_Get_count (&status, GetMPIType(), &len); s.SetSize (len); - MPI_Recv( &s.First(), len, MyGetMPIType(), src, tag, comm, &status); + MPI_Recv( &s.First(), len, GetMPIType(), src, tag, comm, &status); } template - inline int MyMPI_Recv ( NgArray & s, int tag, MPI_Comm comm /* = ng_comm */) + inline int MyMPI_Recv ( NgArray & s, int tag, MPI_Comm comm) { MPI_Status status; int len; @@ -165,10 +111,10 @@ namespace netgen int src = status.MPI_SOURCE; - MPI_Get_count (&status, MyGetMPIType(), &len); + MPI_Get_count (&status, GetMPIType(), &len); s.SetSize (len); - MPI_Recv( &s.First(), len, MyGetMPIType(), src, tag, comm, &status); + MPI_Recv( &s.First(), len, GetMPIType(), src, tag, comm, &status); return src; } @@ -190,22 +136,22 @@ namespace netgen */ template - inline MPI_Request MyMPI_ISend (NgFlatArray s, int dest, int tag, MPI_Comm comm /* = ng_comm */) + inline MPI_Request MyMPI_ISend (NgFlatArray s, int dest, int tag, MPI_Comm comm) { MPI_Request request; - MPI_Isend( &s.First(), s.Size(), MyGetMPIType(), dest, tag, comm, &request); + MPI_Isend( &s.First(), s.Size(), GetMPIType(), dest, tag, comm, &request); return request; } template - inline MPI_Request MyMPI_IRecv (NgFlatArray s, int dest, int tag, MPI_Comm comm /* = ng_comm */) + inline MPI_Request MyMPI_IRecv (NgFlatArray s, int dest, int tag, MPI_Comm comm) { MPI_Request request; - MPI_Irecv( &s.First(), s.Size(), MyGetMPIType(), dest, tag, comm, &request); + MPI_Irecv( &s.First(), s.Size(), GetMPIType(), dest, tag, comm, &request); return request; } - + /* template inline void MyMPI_ISend (NgFlatArray s, int dest, int tag) @@ -232,106 +178,59 @@ namespace netgen receive-table entries will be set */ - /* template inline void MyMPI_ExchangeTable (TABLE & send_data, TABLE & recv_data, int tag, - MPI_Comm comm = MPI_COMM_WORLD) + const NgMPI_Comm & comm) { - int ntasks, rank; - MPI_Comm_size(comm, &ntasks); - MPI_Comm_rank(comm, &rank); - - NgArray requests; - for (int dest = 0; dest < ntasks; dest++) - if (dest != rank) - requests.Append (MyMPI_ISend (send_data[dest], dest, tag, comm)); - - for (int i = 0; i < ntasks-1; i++) - { - MPI_Status status; - MPI_Probe (MPI_ANY_SOURCE, tag, comm, &status); - int size, src = status.MPI_SOURCE; - MPI_Get_count (&status, MPI_INT, &size); - recv_data.SetEntrySize (src, size, sizeof(T)); - requests.Append (MyMPI_IRecv (recv_data[src], src, tag, comm)); - } - MPI_Barrier (comm); - MPI_Waitall (requests.Size(), &requests[0], MPI_STATUS_IGNORE); - } - */ - - template - inline void MyMPI_ExchangeTable (TABLE & send_data, - TABLE & recv_data, int tag, - const NgMPI_Comm & comm /* = ng_comm */) - { - /* - int rank = MyMPI_GetId(comm); - int ntasks = MyMPI_GetNTasks(comm); - */ int rank = comm.Rank(); int ntasks = comm.Size(); - NgArray send_sizes(ntasks); - NgArray recv_sizes(ntasks); + Array send_sizes(ntasks); + Array recv_sizes(ntasks); for (int i = 0; i < ntasks; i++) send_sizes[i] = send_data[i].Size(); + + comm.AllToAll (send_sizes, recv_sizes); - MPI_Alltoall (&send_sizes[0], 1, MPI_INT, - &recv_sizes[0], 1, MPI_INT, comm); - - // in-place is buggy ! -// MPI_Alltoall (MPI_IN_PLACE, 1, MPI_INT, -// &recv_sizes[0], 1, MPI_INT, comm); - - for (int i = 0; i < ntasks; i++) recv_data.SetEntrySize (i, recv_sizes[i], sizeof(T)); - NgArray requests; + Array requests; for (int dest = 0; dest < ntasks; dest++) if (dest != rank && send_data[dest].Size()) - requests.Append (MyMPI_ISend (send_data[dest], dest, tag, comm)); + requests.Append (comm.ISend (FlatArray(send_data[dest]), dest, tag)); for (int dest = 0; dest < ntasks; dest++) if (dest != rank && recv_data[dest].Size()) - requests.Append (MyMPI_IRecv (recv_data[dest], dest, tag, comm)); + requests.Append (comm.IRecv (FlatArray(recv_data[dest]), dest, tag)); - // MPI_Barrier (comm); - MPI_Waitall (requests.Size(), &requests[0], MPI_STATUS_IGNORE); + MyMPI_WaitAll (requests); } - - - - - extern void MyMPI_SendCmd (const char * cmd); extern string MyMPI_RecvCmd (); - - template - inline void MyMPI_Bcast (T & s, MPI_Comm comm /* = ng_comm */) + inline void MyMPI_Bcast (T & s, MPI_Comm comm) { - MPI_Bcast (&s, 1, MyGetMPIType(), 0, comm); + MPI_Bcast (&s, 1, GetMPIType(), 0, comm); } template - inline void MyMPI_Bcast (NgArray & s, NgMPI_Comm comm /* = ng_comm */) + inline void MyMPI_Bcast (NgArray & s, NgMPI_Comm comm) { int size = s.Size(); MyMPI_Bcast (size, comm); // if (MyMPI_GetId(comm) != 0) s.SetSize (size); if (comm.Rank() != 0) s.SetSize (size); - MPI_Bcast (&s[0], size, MyGetMPIType(), 0, comm); + MPI_Bcast (&s[0], size, GetMPIType(), 0, comm); } template - inline void MyMPI_Bcast (NgArray & s, int root, MPI_Comm comm /* = ng_comm */) + inline void MyMPI_Bcast (NgArray & s, int root, MPI_Comm comm) { int id; MPI_Comm_rank(comm, &id); @@ -340,67 +239,21 @@ namespace netgen MPI_Bcast (&size, 1, MPI_INT, root, comm); if (id != root) s.SetSize (size); if ( !size ) return; - MPI_Bcast (&s[0], size, MyGetMPIType(), root, comm); + MPI_Bcast (&s[0], size, GetMPIType(), root, comm); } template - inline void MyMPI_Allgather (const T & send, NgFlatArray recv, MPI_Comm comm /* = ng_comm */) + inline void MyMPI_Allgather (const T & send, NgFlatArray recv, MPI_Comm comm) { - MPI_Allgather( const_cast (&send), 1, MyGetMPIType(), &recv[0], 1, MyGetMPIType(), comm); + MPI_Allgather( const_cast (&send), 1, GetMPIType(), &recv[0], 1, GetMPIType(), comm); } template - inline void MyMPI_Alltoall (NgFlatArray send, NgFlatArray recv, MPI_Comm comm /* = ng_comm */) + inline void MyMPI_Alltoall (NgFlatArray send, NgFlatArray recv, MPI_Comm comm) { - MPI_Alltoall( &send[0], 1, MyGetMPIType(), &recv[0], 1, MyGetMPIType(), comm); + MPI_Alltoall( &send[0], 1, GetMPIType(), &recv[0], 1, GetMPIType(), comm); } -// template -// inline void MyMPI_Alltoall_Block (NgFlatArray send, NgFlatArray recv, int blocklen, MPI_Comm comm = ng_comm) -// { -// MPI_Alltoall( &send[0], blocklen, MyGetMPIType(), &recv[0], blocklen, MyGetMPIType(), comm); -// } - - - - /* - inline void MyMPI_Send ( int *& s, int len, int dest, int tag) - { - int hlen = len; - MPI_Send( &hlen, 1, MPI_INT, dest, tag, MPI_COMM_WORLD); - MPI_Send( s, len, MPI_INT, dest, tag, MPI_COMM_WORLD); - } - - - inline void MyMPI_Recv ( int *& s, int & len, int src, int tag) - { - MPI_Status status; - MPI_Recv( &len, 1, MPI_INT, src, tag, MPI_COMM_WORLD, &status); - if ( s ) - delete [] s; - s = new int [len]; - MPI_Recv( s, len, MPI_INT, src, tag, MPI_COMM_WORLD, &status); - } - - - - inline void MyMPI_Send ( double * s, int len, int dest, int tag) - { - MPI_Send( &len, 1, MPI_INT, dest, tag, MPI_COMM_WORLD); - MPI_Send( s, len, MPI_DOUBLE, dest, tag, MPI_COMM_WORLD); - } - - - inline void MyMPI_Recv ( double *& s, int & len, int src, int tag) - { - MPI_Status status; - MPI_Recv( &len, 1, MPI_INT, src, tag, MPI_COMM_WORLD, &status); - if ( s ) - delete [] s; - s = new double [len]; - MPI_Recv( s, len, MPI_DOUBLE, src, tag, MPI_COMM_WORLD, &status); - } - */ #endif // PARALLEL diff --git a/libsrc/general/ngarray.hpp b/libsrc/general/ngarray.hpp index fa160a8b..05c773a3 100644 --- a/libsrc/general/ngarray.hpp +++ b/libsrc/general/ngarray.hpp @@ -205,6 +205,12 @@ namespace netgen { return ( Pos(elem) >= 0 ); } + + operator FlatArray () const + { + static_assert (BASE==0); + return FlatArray(size, data); + } }; diff --git a/libsrc/gprim/geomobjects.hpp b/libsrc/gprim/geomobjects.hpp index fe8171bf..48f74680 100644 --- a/libsrc/gprim/geomobjects.hpp +++ b/libsrc/gprim/geomobjects.hpp @@ -478,7 +478,7 @@ namespace netgen }; -#ifdef PARALLEL +#ifdef PARALLEL_OLD template <> inline MPI_Datatype MyGetMPIType > () { diff --git a/libsrc/meshing/meshtype.cpp b/libsrc/meshing/meshtype.cpp index f512c683..65e83408 100644 --- a/libsrc/meshing/meshtype.cpp +++ b/libsrc/meshing/meshtype.cpp @@ -30,14 +30,14 @@ namespace netgen (char*)&hp.layer - (char*)&hp, (char*)&hp.singular - (char*)&hp }; MPI_Datatype types[] = { MPI_DOUBLE, MPI_INT, MPI_DOUBLE }; - *testout << "displ = " << displ[0] << ", " << displ[1] << ", " << displ[2] << endl; - *testout << "sizeof = " << sizeof (MeshPoint) << endl; + // *testout << "displ = " << displ[0] << ", " << displ[1] << ", " << displ[2] << endl; + // *testout << "sizeof = " << sizeof (MeshPoint) << endl; MPI_Type_create_struct (3, blocklen, displ, types, &htype); MPI_Type_commit ( &htype ); MPI_Aint lb, ext; MPI_Type_get_extent (htype, &lb, &ext); - *testout << "lb = " << lb << endl; - *testout << "ext = " << ext << endl; + // *testout << "lb = " << lb << endl; + // *testout << "ext = " << ext << endl; ext = sizeof (MeshPoint); MPI_Type_create_resized (htype, lb, ext, &type); MPI_Type_commit ( &type ); diff --git a/libsrc/meshing/parallelmesh.cpp b/libsrc/meshing/parallelmesh.cpp index fac0b2ef..5c869aaa 100644 --- a/libsrc/meshing/parallelmesh.cpp +++ b/libsrc/meshing/parallelmesh.cpp @@ -25,13 +25,19 @@ namespace metis { using namespace metis; #endif +namespace ngcore { + template <> struct MPI_typetrait { + static MPI_Datatype MPIType () { return MPI_INT; } }; +} + namespace netgen { + /* template <> inline MPI_Datatype MyGetMPIType ( ) { return MPI_INT; } - + */ void Mesh :: SendRecvMesh () { diff --git a/libsrc/meshing/paralleltop.cpp b/libsrc/meshing/paralleltop.cpp index c410f425..9968ddd7 100644 --- a/libsrc/meshing/paralleltop.cpp +++ b/libsrc/meshing/paralleltop.cpp @@ -460,24 +460,6 @@ namespace netgen MyMPI_ExchangeTable (send_edges, recv_edges, MPI_TAG_MESH+9, MPI_LocalComm); // cout << "UpdateCoarseGrid - edges mpi-exchange done" << endl; - /* - for (int dest = 1; dest < ntasks; dest++) - { - auto ex2loc = dest2vert[dest-1]; - NgFlatArray recvarray = recv_edges[dest-1]; - for (int ii = 0; ii < recvarray.Size(); ii+=2) - for (int edge : dest2edge[dest-1]) - { - topology.GetEdgeVertices (edge, v1, v2); - INDEX_2 re(ex2loc[recvarray[ii]], - ex2loc[recvarray[ii+1]]); - INDEX_2 es(v1, v2); - if (es == re) - SetDistantEdgeNum(dest, edge); - } - } - */ - for (int dest = 1; dest < ntasks; dest++) { auto ex2loc = dest2vert[dest-1]; @@ -504,8 +486,6 @@ namespace netgen NgProfiler::StopTimer (timere); - // MPI_Barrier (MPI_LocalComm); - // cout << "UpdateCoarseGrid - faces" << endl; if (mesh.GetDimension() == 3) { @@ -543,13 +523,6 @@ namespace netgen for (int dest = 1; dest < ntasks; dest++) if (dest != id) { - /* - loc2exchange = -1; - int cnt = 0; - for (PointIndex pi : mesh.Points().Range()) - if (IsExchangeVert(dest, pi)) - loc2exchange[pi] = cnt++; - */ if (dest2vert[dest-1].Size() == 0) continue; loc2exchange = -1; @@ -575,29 +548,6 @@ namespace netgen TABLE recv_faces(ntasks-1); MyMPI_ExchangeTable (send_faces, recv_faces, MPI_TAG_MESH+9, MPI_LocalComm); // cout << "UpdateCoarseGrid - faces mpi-exchange done" << endl; - - /* - for (int dest = 1; dest < ntasks; dest++) - if (dest != id) - { - loc2exchange = -1; - int cnt = 0; - for (PointIndex pi : dest2vert[dest-1]) - loc2exchange[pi] = cnt++; - - NgFlatArray recvarray = recv_faces[dest-1]; - for (int ii = 0; ii < recvarray.Size(); ii+=3) - for (int face : dest2face[dest-1]) - { - topology.GetFaceVertices (face, verts); - INDEX_3 re(recvarray[ii], recvarray[ii+1], recvarray[ii+2]); - INDEX_3 es(loc2exchange[verts[0]], loc2exchange[verts[1]], loc2exchange[verts[2]]); - if (es == re) - SetDistantFaceNum(dest, face); - } - } - */ - for (int dest = 1; dest < ntasks; dest++) { @@ -622,77 +572,6 @@ namespace netgen } } - - - - - - /* - NgArray glob2loc; - - int maxface = 0; - for (int face = 1; face <= nfa; face++) - maxface = max (maxface, GetGlobalFaceNum (face)); - - // glob2loc.SetSize (nfaglob); - glob2loc.SetSize (maxface); - glob2loc = -1; - - for (int loc = 1; loc <= nfa; loc++) - glob2loc[GetGlobalFaceNum(loc)] = loc; - - cnt_send = 0; - NgArray verts; - for (int face = 1; face <= nfa; face++) - { - topology.GetFaceVertices (face, verts); - for (int dest = 1; dest < ntasks; dest++) - if (IsExchangeVert (dest, verts[0]) && - IsExchangeVert (dest, verts[1]) && - IsExchangeVert (dest, verts[2])) - { - cnt_send[dest-1]+=2; - } - } - - TABLE send_faces(cnt_send); - for (int face = 1; face <= nfa; face++) - { - topology.GetFaceVertices (face, verts); - for (int dest = 1; dest < ntasks; dest++) - { - if (IsExchangeVert (dest, verts[0]) && - IsExchangeVert (dest, verts[1]) && - IsExchangeVert (dest, verts[2])) - { - send_faces.Add (dest-1, GetGlobalFaceNum(face)); - send_faces.Add (dest-1, face); - } - } - } - TABLE recv_faces(ntasks-1); - MyMPI_ExchangeTable (send_faces, recv_faces, MPI_TAG_MESH+8, MPI_LocalComm); - - for (int sender = 1; sender < ntasks; sender ++) - if (id != sender) - { - NgFlatArray recvarray = recv_faces[sender-1]; - - for (int ii = 0; ii < recvarray.Size(); ) - { - int globf = recvarray[ii++]; - int distf = recvarray[ii++]; - - if (globf <= maxface) - { - int locf = glob2loc[globf]; - if (locf != -1) - SetDistantFaceNum (sender, locf); - } - } - } - */ - NgProfiler::StopTimer (timerf); } // cout << "UpdateCoarseGrid - done" << endl; diff --git a/libsrc/meshing/python_mesh.cpp b/libsrc/meshing/python_mesh.cpp index 47dc99c6..8f309d5e 100644 --- a/libsrc/meshing/python_mesh.cpp +++ b/libsrc/meshing/python_mesh.cpp @@ -69,23 +69,6 @@ namespace netgen extern bool netgen_executable_started; extern shared_ptr ng_geometry; extern void Optimize2d (Mesh & mesh, MeshingParameters & mp); - -#ifdef PARALLEL - /** we need allreduce in python-wrapped communicators **/ - template - inline T MyMPI_AllReduceNG (T d, const MPI_Op & op /* = MPI_SUM */, MPI_Comm comm) - { - T global_d; - MPI_Allreduce ( &d, &global_d, 1, MyGetMPIType(), op, comm); - return global_d; - } -#else - // enum { MPI_SUM = 0, MPI_MIN = 1, MPI_MAX = 2 }; - // typedef int MPI_Op; - template - inline T MyMPI_AllReduceNG (T d, const MPI_Op & op /* = MPI_SUM */, MPI_Comm comm) - { return d; } -#endif } @@ -140,15 +123,15 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m) #else .def("WTime", [](NgMPI_Comm & c) { return -1.0; }) #endif - .def("Sum", [](NgMPI_Comm & c, double x) { return MyMPI_AllReduceNG(x, MPI_SUM, c); }) - .def("Min", [](NgMPI_Comm & c, double x) { return MyMPI_AllReduceNG(x, MPI_MIN, c); }) - .def("Max", [](NgMPI_Comm & c, double x) { return MyMPI_AllReduceNG(x, MPI_MAX, c); }) - .def("Sum", [](NgMPI_Comm & c, int x) { return MyMPI_AllReduceNG(x, MPI_SUM, c); }) - .def("Min", [](NgMPI_Comm & c, int x) { return MyMPI_AllReduceNG(x, MPI_MIN, c); }) - .def("Max", [](NgMPI_Comm & c, int x) { return MyMPI_AllReduceNG(x, MPI_MAX, c); }) - .def("Sum", [](NgMPI_Comm & c, size_t x) { return MyMPI_AllReduceNG(x, MPI_SUM, c); }) - .def("Min", [](NgMPI_Comm & c, size_t x) { return MyMPI_AllReduceNG(x, MPI_MIN, c); }) - .def("Max", [](NgMPI_Comm & c, size_t x) { return MyMPI_AllReduceNG(x, MPI_MAX, c); }) + .def("Sum", [](NgMPI_Comm & c, double x) { return c.AllReduce(x, MPI_SUM); }) + .def("Min", [](NgMPI_Comm & c, double x) { return c.AllReduce(x, MPI_MIN); }) + .def("Max", [](NgMPI_Comm & c, double x) { return c.AllReduce(x, MPI_MAX); }) + .def("Sum", [](NgMPI_Comm & c, int x) { return c.AllReduce(x, MPI_SUM); }) + .def("Min", [](NgMPI_Comm & c, int x) { return c.AllReduce(x, MPI_MIN); }) + .def("Max", [](NgMPI_Comm & c, int x) { return c.AllReduce(x, MPI_MAX); }) + .def("Sum", [](NgMPI_Comm & c, size_t x) { return c.AllReduce(x, MPI_SUM); }) + .def("Min", [](NgMPI_Comm & c, size_t x) { return c.AllReduce(x, MPI_MIN); }) + .def("Max", [](NgMPI_Comm & c, size_t x) { return c.AllReduce(x, MPI_MAX); }) .def("SubComm", [](NgMPI_Comm & c, std::vector proc_list) { Array procs(proc_list.size()); for (int i = 0; i < procs.Size(); i++) From e4ef03caac57149c3276c347c213260947c2f0dc Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Wed, 29 Jul 2020 21:17:01 +0200 Subject: [PATCH 091/384] test with Ubuntu 20.04 --- tests/dockerfile_mpi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/dockerfile_mpi b/tests/dockerfile_mpi index 5b093937..220179a8 100644 --- a/tests/dockerfile_mpi +++ b/tests/dockerfile_mpi @@ -1,4 +1,4 @@ -FROM ubuntu:18.04 +FROM ubuntu:20.04 ENV DEBIAN_FRONTEND=noninteractive MAINTAINER Matthias Hochsteger RUN apt-get update && apt-get -y install python3 libpython3-dev python3-pip libxmu-dev tk-dev tcl-dev cmake git g++ libglu1-mesa-dev ccache python3-pytest python3-numpy python3-tk python3-mpi4py clang-tidy python3-distutils clang libopenmpi-dev openmpi-bin gfortran From ba8443922734ed92b1f84c500ddfa14705afb45e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20Sch=C3=B6berl?= Date: Sun, 2 Aug 2020 09:25:23 +0200 Subject: [PATCH 092/384] NgMPI_Communicator by reference, check for valid mpi-comm --- libsrc/core/mpi_wrapper.hpp | 5 +++++ libsrc/include/nginterface_v2.hpp | 2 +- libsrc/interface/nginterface_v2.cpp | 11 +++++++++-- libsrc/meshing/meshclass.hpp | 2 +- 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/libsrc/core/mpi_wrapper.hpp b/libsrc/core/mpi_wrapper.hpp index 11af5f04..c66b2822 100644 --- a/libsrc/core/mpi_wrapper.hpp +++ b/libsrc/core/mpi_wrapper.hpp @@ -89,6 +89,11 @@ namespace ngcore MPI_Comm_free(&comm); } + bool ValidCommunicator() const + { + return valid_comm; + } + NgMPI_Comm & operator= (const NgMPI_Comm & c) { if (refcount) diff --git a/libsrc/include/nginterface_v2.hpp b/libsrc/include/nginterface_v2.hpp index 417bdf72..653f7ead 100644 --- a/libsrc/include/nginterface_v2.hpp +++ b/libsrc/include/nginterface_v2.hpp @@ -276,7 +276,7 @@ namespace netgen void UpdateTopology (); void DoArchive (Archive & archive); - NgMPI_Comm GetCommunicator() const; + const NgMPI_Comm & GetCommunicator() const; virtual ~Ngx_Mesh(); diff --git a/libsrc/interface/nginterface_v2.cpp b/libsrc/interface/nginterface_v2.cpp index f40823e3..e06d83eb 100644 --- a/libsrc/interface/nginterface_v2.cpp +++ b/libsrc/interface/nginterface_v2.cpp @@ -61,8 +61,12 @@ namespace netgen SetGlobalMesh (mesh); } - NgMPI_Comm Ngx_Mesh :: GetCommunicator() const - { return Valid() ? mesh->GetCommunicator() : NgMPI_Comm{}; } + const NgMPI_Comm & Ngx_Mesh :: GetCommunicator() const + { + // return Valid() ? mesh->GetCommunicator() : NgMPI_Comm{}; + if (!Valid()) throw Exception("Ngx_mesh::GetCommunicator: don't have a valid mesh"); + return mesh->GetCommunicator(); + } void Ngx_Mesh :: SaveMesh (ostream & ost) const { @@ -1297,6 +1301,9 @@ void Ngx_Mesh::SetSurfaceElementOrders (int enr, int ox, int oy) std::tuple Ngx_Mesh :: GetDistantProcs (int nodetype, int locnum) const { #ifdef PARALLEL + if (mesh->GetCommunicator().Size() == 1) + return std::tuple(0,nullptr); + switch (nodetype) { case 0: diff --git a/libsrc/meshing/meshclass.hpp b/libsrc/meshing/meshclass.hpp index 28ad665b..4ff21ae8 100644 --- a/libsrc/meshing/meshclass.hpp +++ b/libsrc/meshing/meshclass.hpp @@ -640,7 +640,7 @@ namespace netgen int AddEdgeDescriptor(const EdgeDescriptor & fd) { edgedecoding.Append(fd); return edgedecoding.Size() - 1; } - auto GetCommunicator() const { return this->comm; } + auto & GetCommunicator() const { return this->comm; } void SetCommunicator(NgMPI_Comm acomm); /// From c0909d69c2bb7241d7dbaa915f96cfa065f17e78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20Sch=C3=B6berl?= Date: Sun, 2 Aug 2020 11:33:11 +0200 Subject: [PATCH 093/384] no valid MPI-comm in sequential mode --- libsrc/core/mpi_wrapper.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libsrc/core/mpi_wrapper.hpp b/libsrc/core/mpi_wrapper.hpp index c66b2822..9ebe2e69 100644 --- a/libsrc/core/mpi_wrapper.hpp +++ b/libsrc/core/mpi_wrapper.hpp @@ -289,6 +289,7 @@ namespace ngcore size_t Rank() const { return 0; } size_t Size() const { return 1; } + bool ValidCommunicator() const { return false; } void Barrier() const { ; } operator MPI_Comm() const { return MPI_Comm(); } From 94bed40761e84795b0c66d38dccfba71d6a6a466 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20Sch=C3=B6berl?= Date: Mon, 3 Aug 2020 00:44:28 +0200 Subject: [PATCH 094/384] modernize parallelmesh (Array, mpi_wrapper) --- libsrc/core/mpi_wrapper.hpp | 18 +++++ libsrc/meshing/parallelmesh.cpp | 136 +++++++++++++++++--------------- libsrc/meshing/paralleltop.cpp | 10 +-- 3 files changed, 94 insertions(+), 70 deletions(-) diff --git a/libsrc/core/mpi_wrapper.hpp b/libsrc/core/mpi_wrapper.hpp index 9ebe2e69..48579fe9 100644 --- a/libsrc/core/mpi_wrapper.hpp +++ b/libsrc/core/mpi_wrapper.hpp @@ -238,6 +238,24 @@ namespace ngcore MPI_Alltoall (send.Data(), 1, GetMPIType(), recv.Data(), 1, GetMPIType(), comm); } + + + template + void ScatterRoot (FlatArray send) const + { + if (size == 1) return; + MPI_Scatter (send.Data(), 1, GetMPIType(), + MPI_IN_PLACE, -1, GetMPIType(), 0, comm); + } + + template + void Scatter (T & recv) const + { + if (size == 1) return; + MPI_Scatter (NULL, 0, GetMPIType(), + &recv, 1, GetMPIType(), 0, comm); + } + NgMPI_Comm SubCommunicator (FlatArray procs) const diff --git a/libsrc/meshing/parallelmesh.cpp b/libsrc/meshing/parallelmesh.cpp index 5c869aaa..10cb8eff 100644 --- a/libsrc/meshing/parallelmesh.cpp +++ b/libsrc/meshing/parallelmesh.cpp @@ -76,14 +76,14 @@ namespace netgen void Mesh :: SendMesh () const { - NgArray sendrequests; + Array sendrequests; NgMPI_Comm comm = GetCommunicator(); int id = comm.Rank(); int ntasks = comm.Size(); int dim = GetDimension(); - MyMPI_Bcast(dim, comm); + comm.Bcast(dim); // If the topology is not already updated, we do not need to @@ -97,32 +97,36 @@ namespace netgen PrintMessage ( 3, "Sending nr of elements"); - NgArray num_els_on_proc(ntasks); + Array num_els_on_proc(ntasks); num_els_on_proc = 0; for (ElementIndex ei = 0; ei < GetNE(); ei++) - // num_els_on_proc[(*this)[ei].GetPartition()]++; num_els_on_proc[vol_partition[ei]]++; - MPI_Scatter (&num_els_on_proc[0], 1, MPI_INT, - MPI_IN_PLACE, -1, MPI_INT, 0, comm); + comm.ScatterRoot (num_els_on_proc); - TABLE els_of_proc (num_els_on_proc); + Table els_of_proc (num_els_on_proc); + num_els_on_proc = 0; for (ElementIndex ei = 0; ei < GetNE(); ei++) - // els_of_proc.Add ( (*this)[ei].GetPartition(), ei); - els_of_proc.Add (vol_partition[ei], ei); - + { + auto nr = vol_partition[ei]; + els_of_proc[nr][num_els_on_proc[nr]++] = ei; + } + PrintMessage ( 3, "Building vertex/proc mapping"); - NgArray num_sels_on_proc(ntasks); + Array num_sels_on_proc(ntasks); num_sels_on_proc = 0; for (SurfaceElementIndex ei = 0; ei < GetNSE(); ei++) - // num_sels_on_proc[(*this)[ei].GetPartition()]++; num_sels_on_proc[surf_partition[ei]]++; - TABLE sels_of_proc (num_sels_on_proc); + Table sels_of_proc (num_sels_on_proc); + num_sels_on_proc = 0; for (SurfaceElementIndex ei = 0; ei < GetNSE(); ei++) - // sels_of_proc.Add ( (*this)[ei].GetPartition(), ei); - sels_of_proc.Add (surf_partition[ei], ei); + { + auto nr = surf_partition[ei]; + sels_of_proc[nr][num_sels_on_proc[nr]++] = ei; + } + NgArray num_segs_on_proc(ntasks); num_segs_on_proc = 0; @@ -229,20 +233,31 @@ namespace netgen vert_flag = -1; for (int dest = 1; dest < ntasks; dest++) { - NgFlatArray els = els_of_proc[dest]; + /* + FlatArray els = els_of_proc[dest]; for (int hi = 0; hi < els.Size(); hi++) { const Element & el = (*this) [ els[hi] ]; for (int i = 0; i < el.GetNP(); i++) f(el[i], dest); } - NgFlatArray sels = sels_of_proc[dest]; + */ + for (auto & ei : els_of_proc[dest]) + for (auto pnum : (*this)[ei].PNums()) + f(pnum, dest); + /* + FlatArray sels = sels_of_proc[dest]; for (int hi = 0; hi < sels.Size(); hi++) { const Element2d & el = (*this) [ sels[hi] ]; for (int i = 0; i < el.GetNP(); i++) f(el[i], dest); } + */ + for (auto & ei : sels_of_proc[dest]) + for (auto pnum : (*this)[ei].PNums()) + f(pnum, dest); + NgFlatArray segs = segs_of_proc[dest]; for (int hi = 0; hi < segs.Size(); hi++) { @@ -325,9 +340,6 @@ namespace netgen sendrequests.Append (request); } - NgArray num_distpnums(ntasks); - num_distpnums = 0; - /** Next, we send the identifications themselfs. @@ -385,21 +397,24 @@ namespace netgen } } } - NgArray req_per; + Array req_per; for(int dest = 1; dest < ntasks; dest++) req_per.Append(MyMPI_ISend(pp_data[dest], dest, MPI_TAG_MESH+1, comm)); - MPI_Waitall(req_per.Size(), &req_per[0], MPI_STATUS_IGNORE); + MyMPI_WaitAll(req_per); PrintMessage ( 3, "Sending Vertices - distprocs"); + + Array num_distpnums(ntasks); + num_distpnums = 0; for (int vert = 1; vert <= GetNP(); vert++) { - NgFlatArray procs = procs_of_vert[vert]; - for (int j = 0; j < procs.Size(); j++) - num_distpnums[procs[j]] += 3 * (procs.Size()-1); + FlatArray procs = procs_of_vert[vert]; + for (auto p : procs) + num_distpnums[p] += 3 * (procs.Size()-1); } - TABLE distpnums (num_distpnums); + DynamicTable distpnums (num_distpnums); for (int vert = 1; vert <= GetNP(); vert++) { @@ -415,13 +430,13 @@ namespace netgen } for ( int dest = 1; dest < ntasks; dest ++ ) - sendrequests.Append (MyMPI_ISend (distpnums[dest], dest, MPI_TAG_MESH+1, comm)); + sendrequests.Append (comm.ISend (distpnums[dest], dest, MPI_TAG_MESH+1)); PrintMessage ( 3, "Sending elements" ); - NgArray elarraysize (ntasks); + Array elarraysize (ntasks); elarraysize = 0; for ( int ei = 1; ei <= GetNE(); ei++) { @@ -431,7 +446,7 @@ namespace netgen elarraysize[dest] += 3 + el.GetNP(); } - TABLE elementarrays(elarraysize); + DynamicTable elementarrays(elarraysize); for (int ei = 1; ei <= GetNE(); ei++) { @@ -447,12 +462,13 @@ namespace netgen } for (int dest = 1; dest < ntasks; dest ++ ) - sendrequests.Append (MyMPI_ISend (elementarrays[dest], dest, MPI_TAG_MESH+2, comm)); + // sendrequests.Append (MyMPI_ISend (elementarrays[dest], dest, MPI_TAG_MESH+2, comm)); + sendrequests.Append (comm.ISend (elementarrays[dest], dest, MPI_TAG_MESH+2)); PrintMessage ( 3, "Sending Face Descriptors" ); - NgArray fddata (6 * GetNFD()); + Array fddata (6 * GetNFD()); for (int fdi = 1; fdi <= GetNFD(); fdi++) { fddata[6*fdi-6] = GetFaceDescriptor(fdi).SurfNr(); @@ -464,8 +480,8 @@ namespace netgen } for (int dest = 1; dest < ntasks; dest++) - sendrequests.Append (MyMPI_ISend (fddata, dest, MPI_TAG_MESH+3, comm)); - + sendrequests.Append (comm.ISend (fddata, dest, MPI_TAG_MESH+3)); + /** Surface Elements **/ PrintMessage ( 3, "Sending Surface elements" ); @@ -527,14 +543,14 @@ namespace netgen } } }; - NgArray nlocsel(ntasks), bufsize(ntasks); + Array nlocsel(ntasks), bufsize(ntasks); nlocsel = 0; bufsize = 1; iterate_sels([&](SurfaceElementIndex sei, const Element2d & sel, int dest){ nlocsel[dest]++; bufsize[dest] += 4 + 2*sel.GetNP(); }); - TABLE selbuf(bufsize); + DynamicTable selbuf(bufsize); for (int dest = 1; dest < ntasks; dest++ ) selbuf.Add (dest, nlocsel[dest]); iterate_sels([&](SurfaceElementIndex sei, const auto & sel, int dest) { @@ -550,7 +566,7 @@ namespace netgen }); // distribute sel data for (int dest = 1; dest < ntasks; dest++) - sendrequests.Append (MyMPI_ISend(selbuf[dest], dest, MPI_TAG_MESH+4, comm)); + sendrequests.Append (comm.ISend(selbuf[dest], dest, MPI_TAG_MESH+4)); /** Segments **/ @@ -682,7 +698,7 @@ namespace netgen nloc_seg[dest]++; bufsize[dest] += 14; }); - TABLE segm_buf(bufsize); + DynamicTable segm_buf(bufsize); iterate_segs2([&](auto segi, const auto & seg, int dest) { segm_buf.Add (dest, segi); @@ -702,11 +718,11 @@ namespace netgen }); // distrubute segment data for (int dest = 1; dest < ntasks; dest++) - sendrequests.Append (MyMPI_ISend(segm_buf[dest], dest, MPI_TAG_MESH+5, comm)); + sendrequests.Append (comm.ISend(segm_buf[dest], dest, MPI_TAG_MESH+5)); PrintMessage ( 3, "now wait ..."); - MPI_Waitall (sendrequests.Size(), &sendrequests[0], MPI_STATUS_IGNORE); + MyMPI_WaitAll (sendrequests); // clean up MPI-datatypes we allocated earlier for (auto t : point_types) @@ -752,9 +768,9 @@ namespace netgen PrintMessage ( 3, "wait for names"); - MPI_Waitall (sendrequests.Size(), &sendrequests[0], MPI_STATUS_IGNORE); + MyMPI_WaitAll (sendrequests); - MPI_Barrier(comm); + comm.Barrier(); PrintMessage( 3, "Clean up local memory"); @@ -818,22 +834,19 @@ namespace netgen int ntasks = comm.Size(); int dim; - MyMPI_Bcast(dim, comm); + comm.Bcast(dim); SetDimension(dim); // Receive number of local elements int nelloc; - MPI_Scatter (NULL, 0, MPI_INT, - &nelloc, 1, MPI_INT, 0, comm); + comm.Scatter (nelloc); paralleltop -> SetNE (nelloc); - // string st; - // receive vertices NgProfiler::StartTimer (timer_pts); - NgArray verts; - MyMPI_Recv (verts, 0, MPI_TAG_MESH+1, comm); + Array verts; + comm.Recv (verts, 0, MPI_TAG_MESH+1); int numvert = verts.Size(); paralleltop -> SetNV (numvert); @@ -855,16 +868,13 @@ namespace netgen MPI_Status status; MPI_Recv( points.Data(), numvert, mptype, 0, MPI_TAG_MESH+1, comm, &status); - NgArray pp_data; - MyMPI_Recv(pp_data, 0, MPI_TAG_MESH+1, comm); + Array pp_data; + comm.Recv(pp_data, 0, MPI_TAG_MESH+1); int maxidentnr = pp_data[0]; auto & idents = GetIdentifications(); for (int idnr = 1; idnr < maxidentnr+1; idnr++) - { - - idents.SetType(idnr, (Identifications::ID_TYPE)pp_data[idnr]); - } + idents.SetType(idnr, (Identifications::ID_TYPE)pp_data[idnr]); int offset = 2*maxidentnr+1; for(int idnr = 1; idnr < maxidentnr+1; idnr++) @@ -879,8 +889,8 @@ namespace netgen } } - NgArray dist_pnums; - MyMPI_Recv (dist_pnums, 0, MPI_TAG_MESH+1, comm); + Array dist_pnums; + comm.Recv (dist_pnums, 0, MPI_TAG_MESH+1); for (int hi = 0; hi < dist_pnums.Size(); hi += 3) paralleltop -> @@ -890,8 +900,8 @@ namespace netgen *testout << "got " << numvert << " vertices" << endl; { - NgArray elarray; - MyMPI_Recv (elarray, 0, MPI_TAG_MESH+2, comm); + Array elarray; + comm.Recv (elarray, 0, MPI_TAG_MESH+2); NgProfiler::RegionTimer reg(timer_els); @@ -911,8 +921,8 @@ namespace netgen } { - NgArray fddata; - MyMPI_Recv (fddata, 0, MPI_TAG_MESH+3, comm); + Array fddata; + comm.Recv (fddata, 0, MPI_TAG_MESH+3); for (int i = 0; i < fddata.Size(); i += 6) { int faceind = AddFaceDescriptor @@ -925,9 +935,9 @@ namespace netgen { NgProfiler::RegionTimer reg(timer_sels); - NgArray selbuf; + Array selbuf; - MyMPI_Recv ( selbuf, 0, MPI_TAG_MESH+4, comm); + comm.Recv ( selbuf, 0, MPI_TAG_MESH+4); int ii = 0; int sel = 0; @@ -1032,7 +1042,7 @@ namespace netgen write_names(cd2names); write_names(cd3names); - MPI_Barrier(comm); + comm.Barrier(); int timerloc = NgProfiler::CreateTimer ("Update local mesh"); int timerloc2 = NgProfiler::CreateTimer ("CalcSurfacesOfNode"); diff --git a/libsrc/meshing/paralleltop.cpp b/libsrc/meshing/paralleltop.cpp index 9968ddd7..06c08ab5 100644 --- a/libsrc/meshing/paralleltop.cpp +++ b/libsrc/meshing/paralleltop.cpp @@ -25,11 +25,7 @@ namespace netgen { *testout << "ParallelMeshTopology::Reset" << endl; - NgMPI_Comm comm = mesh.GetCommunicator(); - int id = comm.Rank(); - int ntasks = comm.Size(); - - if ( ntasks == 1 ) return; + if ( mesh.GetCommunicator().Size() == 1 ) return; int ned = mesh.GetTopology().GetNEdges(); int nfa = mesh.GetTopology().GetNFaces(); @@ -162,10 +158,10 @@ namespace netgen sendarray.Append (topology.GetSurfaceElementFace (el)); } - NgArray sendrequests; + Array sendrequests; for (int dest = 1; dest < ntasks; dest++) sendrequests.Append (MyMPI_ISend (*sendarrays[dest], dest, MPI_TAG_MESH+10, comm)); - MPI_Waitall (sendrequests.Size(), &sendrequests[0], MPI_STATUS_IGNORE); + MyMPI_WaitAll (sendrequests); for (int dest = 1; dest < ntasks; dest++) delete sendarrays[dest]; From 698192ed720ab9a7402f59221ddcfe9eda9431e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20Sch=C3=B6berl?= Date: Mon, 3 Aug 2020 14:45:32 +0200 Subject: [PATCH 095/384] FlatArray for C-array --- libsrc/core/array.hpp | 4 ++++ libsrc/core/mpi_wrapper.hpp | 8 ++++---- libsrc/meshing/parallelmesh.cpp | 7 +++++-- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/libsrc/core/array.hpp b/libsrc/core/array.hpp index a1161001..2c6fc436 100644 --- a/libsrc/core/array.hpp +++ b/libsrc/core/array.hpp @@ -450,6 +450,10 @@ namespace ngcore : size(asize), data (lh.Alloc (asize)) { ; } + template + NETGEN_INLINE FlatArray(T (&ar)[N]) + : size(N), data(ar) { } + /// the size NETGEN_INLINE size_t Size() const { return size; } diff --git a/libsrc/core/mpi_wrapper.hpp b/libsrc/core/mpi_wrapper.hpp index 48579fe9..102bc064 100644 --- a/libsrc/core/mpi_wrapper.hpp +++ b/libsrc/core/mpi_wrapper.hpp @@ -171,7 +171,7 @@ namespace ngcore } template())> - MPI_Request ISend (const FlatArray & s, int dest, int tag) const + MPI_Request ISend (FlatArray s, int dest, int tag) const { MPI_Request request; MPI_Isend (s.Data(), s.Size(), GetMPIType(), dest, tag, comm, &request); @@ -187,7 +187,7 @@ namespace ngcore } template())> - MPI_Request IRecv (const FlatArray & s, int src, int tag) const + MPI_Request IRecv (FlatArray s, int src, int tag) const { MPI_Request request; MPI_Irecv (s.Data(), s.Size(), GetMPIType(), src, tag, comm, &request); @@ -330,13 +330,13 @@ namespace ngcore MPI_Request ISend (T & val, int dest, int tag) const { return 0; } template - MPI_Request ISend (const FlatArray & s, int dest, int tag) const { return 0; } + MPI_Request ISend (FlatArray s, int dest, int tag) const { return 0; } template MPI_Request IRecv (T & val, int dest, int tag) const { return 0; } template - MPI_Request IRecv (const FlatArray & s, int src, int tag) const { return 0; } + MPI_Request IRecv (FlatArray s, int src, int tag) const { return 0; } template T Reduce (T d, const MPI_Op & op, int root = 0) const { return d; } diff --git a/libsrc/meshing/parallelmesh.cpp b/libsrc/meshing/parallelmesh.cpp index 10cb8eff..264b4f84 100644 --- a/libsrc/meshing/parallelmesh.cpp +++ b/libsrc/meshing/parallelmesh.cpp @@ -740,7 +740,8 @@ namespace netgen nnames[3] = GetNCD3Names(); int tot_nn = nnames[0] + nnames[1] + nnames[2] + nnames[3]; for( int k = 1; k < ntasks; k++) - (void) MPI_Isend(nnames, 4, MPI_INT, k, MPI_TAG_MESH+6, comm, &sendrequests[k]); + sendrequests[k] = comm.ISend(FlatArray(nnames), k, MPI_TAG_MESH+6); + // (void) MPI_Isend(nnames, 4, MPI_INT, k, MPI_TAG_MESH+6, comm, &sendrequests[k]); auto iterate_names = [&](auto func) { for (int k = 0; k < nnames[0]; k++) func(materials[k]); for (int k = 0; k < nnames[1]; k++) func(bcnames[k]); @@ -1013,7 +1014,9 @@ namespace netgen /** Recv bc-names **/ int nnames[4] = {0,0,0,0}; - MPI_Recv(nnames, 4, MPI_INT, 0, MPI_TAG_MESH+6, comm, MPI_STATUS_IGNORE); + // MPI_Recv(nnames, 4, MPI_INT, 0, MPI_TAG_MESH+6, comm, MPI_STATUS_IGNORE); + comm.Recv(FlatArray(nnames), 0, MPI_TAG_MESH+6); + // cout << "nnames = " << FlatArray(nnames) << endl; materials.SetSize(nnames[0]); bcnames.SetSize(nnames[1]); cd2names.SetSize(nnames[2]); From 4682e6915cc2a046f3159414550a545b523ad545 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Tue, 4 Aug 2020 12:59:03 +0200 Subject: [PATCH 096/384] remove FlatArray for C-Array, use ArrayMem --- libsrc/core/array.hpp | 4 ---- libsrc/meshing/parallelmesh.cpp | 8 ++++---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/libsrc/core/array.hpp b/libsrc/core/array.hpp index 2c6fc436..a1161001 100644 --- a/libsrc/core/array.hpp +++ b/libsrc/core/array.hpp @@ -450,10 +450,6 @@ namespace ngcore : size(asize), data (lh.Alloc (asize)) { ; } - template - NETGEN_INLINE FlatArray(T (&ar)[N]) - : size(N), data(ar) { } - /// the size NETGEN_INLINE size_t Size() const { return size; } diff --git a/libsrc/meshing/parallelmesh.cpp b/libsrc/meshing/parallelmesh.cpp index 264b4f84..7e7b7523 100644 --- a/libsrc/meshing/parallelmesh.cpp +++ b/libsrc/meshing/parallelmesh.cpp @@ -733,14 +733,14 @@ namespace netgen sendrequests.SetSize(3*ntasks); /** Send bc/mat/cd*-names **/ // nr of names - int nnames[4] = {0,0,0,0}; + ArrayMem nnames{0,0,0,0}; nnames[0] = materials.Size(); nnames[1] = bcnames.Size(); nnames[2] = GetNCD2Names(); nnames[3] = GetNCD3Names(); int tot_nn = nnames[0] + nnames[1] + nnames[2] + nnames[3]; for( int k = 1; k < ntasks; k++) - sendrequests[k] = comm.ISend(FlatArray(nnames), k, MPI_TAG_MESH+6); + sendrequests[k] = comm.ISend(nnames, k, MPI_TAG_MESH+6); // (void) MPI_Isend(nnames, 4, MPI_INT, k, MPI_TAG_MESH+6, comm, &sendrequests[k]); auto iterate_names = [&](auto func) { for (int k = 0; k < nnames[0]; k++) func(materials[k]); @@ -1013,9 +1013,9 @@ namespace netgen } /** Recv bc-names **/ - int nnames[4] = {0,0,0,0}; + ArrayMem nnames{0,0,0,0}; // MPI_Recv(nnames, 4, MPI_INT, 0, MPI_TAG_MESH+6, comm, MPI_STATUS_IGNORE); - comm.Recv(FlatArray(nnames), 0, MPI_TAG_MESH+6); + comm.Recv(nnames, 0, MPI_TAG_MESH+6); // cout << "nnames = " << FlatArray(nnames) << endl; materials.SetSize(nnames[0]); bcnames.SetSize(nnames[1]); From 254257d406eeadd8e5dec47e4c19ea5e6fdd605a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20Sch=C3=B6berl?= Date: Tue, 4 Aug 2020 16:29:59 +0200 Subject: [PATCH 097/384] timer in MPI wrappes --- libsrc/core/mpi_wrapper.hpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/libsrc/core/mpi_wrapper.hpp b/libsrc/core/mpi_wrapper.hpp index 102bc064..f26e66ec 100644 --- a/libsrc/core/mpi_wrapper.hpp +++ b/libsrc/core/mpi_wrapper.hpp @@ -8,6 +8,7 @@ #include "array.hpp" #include "exception.hpp" +#include "profiler.hpp" namespace ngcore { @@ -122,6 +123,7 @@ namespace ngcore int Rank() const { return rank; } int Size() const { return size; } void Barrier() const { + static Timer t("MPI - Barrier"); RegionTimer reg(t); if (size > 1) MPI_Barrier (comm); } @@ -200,6 +202,7 @@ namespace ngcore template ())> T Reduce (T d, const MPI_Op & op, int root = 0) const { + static Timer t("MPI - Reduce"); RegionTimer reg(t); if (size == 1) return d; T global_d; @@ -210,6 +213,7 @@ namespace ngcore template ())> T AllReduce (T d, const MPI_Op & op) const { + static Timer t("MPI - AllReduce"); RegionTimer reg(t); if (size == 1) return d; T global_d; @@ -272,6 +276,7 @@ namespace ngcore NETGEN_INLINE void MyMPI_WaitAll (FlatArray requests) { + static Timer t("MPI - WaitAll"); RegionTimer reg(t); if (!requests.Size()) return; MPI_Waitall (requests.Size(), requests.Data(), MPI_STATUSES_IGNORE); } From 7dbd9e6b549c8ad408d7113291932a568aef3f4c Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Tue, 4 Aug 2020 11:12:47 +0200 Subject: [PATCH 098/384] CGNS write support --- libsrc/interface/rw_cgns.cpp | 259 ++++++++++++++++++++++++++++++++- libsrc/interface/writeuser.cpp | 4 + libsrc/interface/writeuser.hpp | 7 +- libsrc/meshing/python_mesh.cpp | 7 + 4 files changed, 272 insertions(+), 5 deletions(-) diff --git a/libsrc/interface/rw_cgns.cpp b/libsrc/interface/rw_cgns.cpp index 05761577..53532883 100644 --- a/libsrc/interface/rw_cgns.cpp +++ b/libsrc/interface/rw_cgns.cpp @@ -49,19 +49,19 @@ namespace netgen::cg Element2d ReadCGNSElement2D( ElementType_t type, FlatArray verts ) { - static constexpr int map_tri3[] = {0,2,1}; +// static constexpr int map_tri3[] = {0,2,1}; static constexpr int map_tri6[] = {0,2,1,3,5,4}; // untested - static constexpr int map_quad4[] = {0,3,2,1}; +// static constexpr int map_quad4[] = {0,3,2,1}; static constexpr int map_quad8[] = {0,3,2,1,4,7,6,5}; // untested const int * map = nullptr; switch(type) { case TRI_3: - map = map_tri3; +// map = map_tri3; break; case QUAD_4: - map = map_quad4; +// map = map_quad4; break; case TRI_6: map = map_tri6; @@ -117,6 +117,145 @@ namespace netgen::cg return el; } + void WriteCGNSElement( const Segment & el, Array & verts ) + { + verts.Append(BAR_2); + verts.Append(el[0]); + verts.Append(el[1]); + } + + void WriteCGNSElement( const Element2d & el, Array & verts ) + { + static constexpr int map_tri6[] = {0,2,1,3,5,4}; // untested + static constexpr int map_quad8[] = {0,3,2,1,4,7,6,5}; // untested + + ElementType_t type; + + const int * map = nullptr; + switch(el.GetType()) + { + case TRIG: + type = TRI_3; + break; + case QUAD: + type = QUAD_4; + break; + case TRIG6: + type = TRI_6; + map = map_tri6; + break; + case QUAD8: + type = QUAD_8; + map = map_quad8; + break; + // TODO: Second order elements + default: + throw Exception("Write CGNS: unknown element type " + ToString(el.GetType())); + } + + verts.Append(type); + + for (auto i : Range(el.GetNP())) + verts.Append(el[i]); + } + + void WriteCGNSElement( const Element & el, Array & verts ) + { + static constexpr int map_tet4[] = {0,2,1,3}; + static constexpr int map_prism6[] = {0,2,1,3,5,4}; + static constexpr int map_pyra5[] = {0,3,2,1,4}; + static constexpr int map_hexa8[] = {0,3,2,1,4,7,6,5}; + + ElementType_t type; + + const int * map = nullptr; + switch(el.GetType()) + { + case TET: + map = map_tet4; + type = TETRA_4; + break; + case PYRAMID: + type = PYRA_5; + map = map_pyra5; + break; + case PRISM: + type = PENTA_6; + map = map_prism6; + break; + case HEX: + type = HEXA_8; + map = map_hexa8; + break; + // TODO: Second order elements + default: + throw Exception("Write CGNS: unknown element type " + ToString(el.GetType())); + } + + verts.Append(type); + + for (auto i : Range(el.GetNP())) + verts.Append(el[map[i]]); + } + + int WriteCGNSRegion( const Mesh & mesh, int dim, int index, int fn, int base, int zone, int ne_before ) + { + int meshdim = mesh.GetDimension(); + int codim = meshdim-dim; + + if(codim < 0 || codim > 2) + return 0; + + // make sure that each material/boundary name is unique + string prefix[] = { "dom_", "bnd_", "bbnd_" }; + string name = prefix[meshdim-dim] + ToString(index) + "_"; + + if(codim==0) name += mesh.GetMaterial(index+1); + if(codim==1) name += *mesh.GetBCNamePtr(index); + if(codim==2) name += mesh.GetCD2Name(index); + + int ne = 0; + Array data; + + if(dim==3) + for(const auto el : mesh.VolumeElements()) + if(el.GetIndex()==index) + { + ne++; + WriteCGNSElement(el, data); + } + + if(dim==2) + for(const auto el : mesh.SurfaceElements()) + if(el.GetIndex()==index) + { + ne++; + WriteCGNSElement(el, data); + } + + if(dim==1) + for(const auto el : mesh.LineSegments()) + if(el.si==index) + { + ne++; + WriteCGNSElement(el, data); + } + + if(ne==0) + return 0; + + int section; + int start = 1; + int end = ne; +#if CGNS_VERSION < 3400 + cg_section_write(fn,base,zone, name.c_str(), MIXED, ne_before+1, ne_before+ne, 0, &data[0], §ion); +#else + cg_poly_section_write(fn,base,zone, name.c_str(), MIXED, ne_before+1, ne_before+ne, 0, &data[0], nullptr, §ion); +#endif + + return ne; + } + // maps cgns node type to ngsolve node type // enum NODE_TYPE { NT_VERTEX = 0, NT_EDGE = 1, NT_FACE = 2, NT_CELL = 3, NT_ELEMENT = 4, NT_FACET = 5 }; int getNodeType( GridLocation_t location ) @@ -136,6 +275,23 @@ namespace netgen::cg } } + GridLocation_t getCGNodeType( int node_type ) + { + switch(node_type) + { + case 0: + return Vertex; + case 1: + return EdgeCenter; + case 2: + return FaceCenter; + case 3: + return CellCenter; + default: + throw Exception("Write CGNS: unknown node type " + ToString(node_type)); + } + } + struct Solution { @@ -533,6 +689,90 @@ namespace netgen cg_close(fn); return std::make_tuple(mesh, names, values, locations); } + + void WriteCGNSMesh (const Mesh & mesh, int fn, int & base, int & zone) + { + int dim = mesh.GetDimension(); + cg_base_write(fn, "mesh", dim, dim, &base); + + int nv = static_cast(mesh.GetNV()); + int ne = mesh.GetNE(); + + Array x, y, z; + for(auto & p : mesh.Points()) + { + x.Append(p[0]); + y.Append(p[1]); + z.Append(p[2]); + } + + cgsize_t isize[3] = { nv, ne, 0 }; + cg_zone_write(fn,base, "mesh", isize, Unstructured, &zone); + + int coord; + cg_coord_write(fn,base,zone, RealDouble, "CoordinateX", &x[0], &coord); + cg_coord_write(fn,base,zone, RealDouble, "CoordinateY", &y[0], &coord); + cg_coord_write(fn,base,zone, RealDouble, "CoordinateZ", &z[0], &coord); + + int imax3 = 0; + for(const auto & el : mesh.VolumeElements()) + imax3 = max(imax3, el.GetIndex()); + + int imax2 = 0; + for(const auto & el : mesh.SurfaceElements()) + imax2 = max(imax2, el.GetIndex()); + + int imax1 = 0; + for(const auto & el : mesh.LineSegments()) + imax1 = max(imax1, el.si); + + int ne_written = 0; + int meshdim = mesh.GetDimension(); + + for(const auto i : IntRange(imax3)) + ne_written += cg::WriteCGNSRegion(mesh, 3, i+1, fn, base, zone, ne_written); + + for(const auto i : IntRange(imax2)) + ne_written += cg::WriteCGNSRegion(mesh, 2, i+1, fn, base, zone, ne_written); + + for(const auto i : IntRange(imax1)) + ne_written += cg::WriteCGNSRegion(mesh, 1, i+1, fn, base, zone, ne_written); + + } + + void WriteCGNSMesh (const Mesh & mesh, const string & filename) + { + static Timer tall("CGNS::WriteMesh"); RegionTimer rtall(tall); + int fn, base, zone; + cg_open(filename.c_str(),CG_MODE_WRITE,&fn); + + WriteCGNSMesh(mesh, fn, base, zone); + + cg_close(fn); + } + + + void WriteCGNSFile(shared_ptr mesh, string filename, vector fields, vector> values, vector locations) + { + static Timer tall("CGNS::WriteFile"); RegionTimer rtall(tall); + int fn, base, zone; + cg_open(filename.c_str(),CG_MODE_WRITE,&fn); + + WriteCGNSMesh(*mesh, fn, base, zone); + + for(auto i : IntRange(fields.size())) + { + int section, field; + string name = "solution_" + ToString(i); + + + cg_sol_write(fn, base, zone, name.c_str(), cg::getCGNodeType(locations[i]), §ion); + cg_field_write(fn, base, zone, section, RealDouble, fields[i].c_str(), &values[i][0], &field); + } + + cg_close(fn); + } + } #else // NG_CGNS @@ -548,6 +788,17 @@ namespace netgen { throw Exception("Netgen was built without CGNS support"); } + + void WriteCGNSMesh (const Mesh & mesh, const string & filename) + { + PrintMessage(1, "Could not write CGNS mesh: Netgen was built without CGNS support"); + } + + void WriteCGNSFile(shared_ptr mesh, string filename, vector fields, vector> values, vector locations) + { + throw Exception("Netgen was built without CGNS support"); + } + } #endif // NG_CGNS diff --git a/libsrc/interface/writeuser.cpp b/libsrc/interface/writeuser.cpp index 56f61fec..90dacfd3 100644 --- a/libsrc/interface/writeuser.cpp +++ b/libsrc/interface/writeuser.cpp @@ -43,6 +43,7 @@ namespace netgen "OpenFOAM 1.5+ Compressed", "*", "JCMwave Format", ".jcm", "TET Format", ".tet", + "CGNS Format", ".cgns", // { "Chemnitz Format" }, 0 }; @@ -144,6 +145,9 @@ bool WriteUserFormat (const string & format, WriteTETFormat( mesh, filename);//, "High Frequency" ); #endif + else if (format == "CGNS Format") + WriteCGNSMesh( mesh, filename); + else { return 1; diff --git a/libsrc/interface/writeuser.hpp b/libsrc/interface/writeuser.hpp index 8c58ea5f..b40b8706 100644 --- a/libsrc/interface/writeuser.hpp +++ b/libsrc/interface/writeuser.hpp @@ -153,10 +153,15 @@ extern void ReadFNFFormat (Mesh & mesh, extern void DLL_HEADER ReadCGNSMesh (Mesh & mesh, const string & filename); -// Read Mesh and solutions from CGNS file +extern void DLL_HEADER WriteCGNSMesh (const Mesh & mesh, + const string & filename); + +// read/write mesh and solutions from CGNS file extern tuple, vector, vector>, vector> DLL_HEADER ReadCGNSFile(string filename, int base); +extern void DLL_HEADER WriteCGNSFile(shared_ptr mesh,string filename, vector fields, + vector> values, vector locations); void WriteDolfinFormat (const Mesh & mesh, diff --git a/libsrc/meshing/python_mesh.cpp b/libsrc/meshing/python_mesh.cpp index 8f309d5e..a7edcec5 100644 --- a/libsrc/meshing/python_mesh.cpp +++ b/libsrc/meshing/python_mesh.cpp @@ -1192,6 +1192,13 @@ grow_edges : bool = False m.def("ReadCGNSFile", &ReadCGNSFile, py::arg("filename"), py::arg("base")=1, "Read mesh and solution vectors from CGNS file"); + m.def("WriteCGNSFile", &WriteCGNSFile, py::arg("mesh"), py::arg("filename"), py::arg("names"), py::arg("values"), py::arg("locations"), + R"(Write mesh and solution vectors to CGNS file, possible values for locations: + Vertex = 0 + EdgeCenter = 1 + FaceCenter = 2 + CellCenter = 3 + )"); py::class_> (m, "SurfaceGeometry") .def(py::init<>()) From 42a01b5c21f068606de5b30d60421b92122a790f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20Sch=C3=B6berl?= Date: Tue, 4 Aug 2020 23:36:19 +0200 Subject: [PATCH 099/384] use MPI_DATAYPE_NULL thx stefanozampini --- libsrc/meshing/meshtype.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libsrc/meshing/meshtype.cpp b/libsrc/meshing/meshtype.cpp index 65e83408..cd8e2329 100644 --- a/libsrc/meshing/meshtype.cpp +++ b/libsrc/meshing/meshtype.cpp @@ -20,8 +20,8 @@ namespace netgen #ifdef PARALLEL MPI_Datatype MeshPoint :: MyGetMPIType ( ) { - static MPI_Datatype type = NULL; - static MPI_Datatype htype = NULL; + static MPI_Datatype type = MPI_DATATYPE_NULL; + static MPI_Datatype htype = MPI_DATATYPE_NULL; if (!type) { MeshPoint hp; From 3864eb2e35f5cbcc90272dbb8c836f2fedd2a3ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20Sch=C3=B6berl?= Date: Tue, 4 Aug 2020 23:50:11 +0200 Subject: [PATCH 100/384] use MPI_DATAYPE_NULL thx stefanozampini --- libsrc/meshing/meshtype.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsrc/meshing/meshtype.cpp b/libsrc/meshing/meshtype.cpp index cd8e2329..0730c9d8 100644 --- a/libsrc/meshing/meshtype.cpp +++ b/libsrc/meshing/meshtype.cpp @@ -22,7 +22,7 @@ namespace netgen { static MPI_Datatype type = MPI_DATATYPE_NULL; static MPI_Datatype htype = MPI_DATATYPE_NULL; - if (!type) + if (type == MPI_DATATYPE_NULL) { MeshPoint hp; int blocklen[] = { 3, 1, 1 }; From 3c8f1877c9a476f4749701b58d2a6012f748ed35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20Sch=C3=B6berl?= Date: Wed, 5 Aug 2020 01:11:26 +0200 Subject: [PATCH 101/384] more mpi calls from ngcore --- libsrc/core/mpi_wrapper.hpp | 15 +++++++++++++++ libsrc/general/mpi_interface.hpp | 10 ++++++++-- libsrc/meshing/parallelmesh.cpp | 6 ++++-- libsrc/meshing/paralleltop.cpp | 5 +++-- 4 files changed, 30 insertions(+), 6 deletions(-) diff --git a/libsrc/core/mpi_wrapper.hpp b/libsrc/core/mpi_wrapper.hpp index f26e66ec..b2e32731 100644 --- a/libsrc/core/mpi_wrapper.hpp +++ b/libsrc/core/mpi_wrapper.hpp @@ -134,6 +134,10 @@ namespace ngcore void Send (T & val, int dest, int tag) const { MPI_Send (&val, 1, GetMPIType(), dest, tag, comm); } + + void Send (const std::string & s, int dest, int tag) const { + MPI_Send( const_cast (&s[0]), s.length(), MPI_CHAR, dest, tag, comm); + } template())> void Send(FlatArray s, int dest, int tag) const { @@ -145,6 +149,17 @@ namespace ngcore MPI_Recv (&val, 1, GetMPIType(), src, tag, comm, MPI_STATUS_IGNORE); } + void Recv (std::string & s, int src, int tag) const { + MPI_Status status; + int len; + MPI_Probe (src, tag, comm, &status); + MPI_Get_count (&status, MPI_CHAR, &len); + // s.assign (len, ' '); + s.resize (len); + MPI_Recv( &s[0], len, MPI_CHAR, src, tag, comm, MPI_STATUS_IGNORE); + } + + template ())> void Recv (FlatArray s, int src, int tag) const { MPI_Recv (s.Data(), s.Size(), GetMPIType (), src, tag, comm, MPI_STATUS_IGNORE); diff --git a/libsrc/general/mpi_interface.hpp b/libsrc/general/mpi_interface.hpp index 08e7e85a..82f40720 100644 --- a/libsrc/general/mpi_interface.hpp +++ b/libsrc/general/mpi_interface.hpp @@ -59,11 +59,13 @@ namespace netgen MPI_Recv( &i, 1, MPI_INT, src, tag, comm, &status); } + [[deprecated("mympi_send string, use comm.Send instead")]] inline void MyMPI_Send (const string & s, int dest, int tag, MPI_Comm comm) { MPI_Send( const_cast (s.c_str()), s.length(), MPI_CHAR, dest, tag, comm); } + [[deprecated("mympi_revc string, use comm.Recv instead")]] inline void MyMPI_Recv (string & s, int src, int tag, MPI_Comm comm) { MPI_Status status; @@ -76,14 +78,15 @@ namespace netgen - template + [[deprecated("mympi_send ngflatarray, use comm.send instead")]] inline void MyMPI_Send (NgFlatArray s, int dest, int tag, MPI_Comm comm) { MPI_Send( &s.First(), s.Size(), GetMPIType(), dest, tag, comm); } template + [[deprecated("mympi_recv ngflatarray, use comm.Recv instead")]] inline void MyMPI_Recv ( NgFlatArray s, int src, int tag, MPI_Comm comm) { MPI_Status status; @@ -136,6 +139,7 @@ namespace netgen */ template + [[deprecated("mympi_isend ngflatarray, use comm.send instead")]] inline MPI_Request MyMPI_ISend (NgFlatArray s, int dest, int tag, MPI_Comm comm) { MPI_Request request; @@ -143,8 +147,8 @@ namespace netgen return request; } - template + [[deprecated("mympi_irecv ngflatarray, use comm.recv instead")]] inline MPI_Request MyMPI_IRecv (NgFlatArray s, int dest, int tag, MPI_Comm comm) { MPI_Request request; @@ -243,12 +247,14 @@ namespace netgen } template + [[deprecated("mympi_allgather deprecated, use comm.allgather")]] inline void MyMPI_Allgather (const T & send, NgFlatArray recv, MPI_Comm comm) { MPI_Allgather( const_cast (&send), 1, GetMPIType(), &recv[0], 1, GetMPIType(), comm); } template + [[deprecated("mympi_alltoall deprecated, use comm.alltoall")]] inline void MyMPI_Alltoall (NgFlatArray send, NgFlatArray recv, MPI_Comm comm) { MPI_Alltoall( &send[0], 1, GetMPIType(), &recv[0], 1, GetMPIType(), comm); diff --git a/libsrc/meshing/parallelmesh.cpp b/libsrc/meshing/parallelmesh.cpp index 7e7b7523..9af0d7a6 100644 --- a/libsrc/meshing/parallelmesh.cpp +++ b/libsrc/meshing/parallelmesh.cpp @@ -321,7 +321,8 @@ namespace netgen for (int dest = 1; dest < ntasks; dest++) { NgFlatArray verts = verts_of_proc[dest]; - sendrequests.Append (MyMPI_ISend (verts, dest, MPI_TAG_MESH+1, comm)); + // sendrequests.Append (MyMPI_ISend (verts, dest, MPI_TAG_MESH+1, comm)); + sendrequests.Append (comm.ISend (FlatArray(verts), dest, MPI_TAG_MESH+1)); MPI_Datatype mptype = MeshPoint::MyGetMPIType(); @@ -399,7 +400,8 @@ namespace netgen } Array req_per; for(int dest = 1; dest < ntasks; dest++) - req_per.Append(MyMPI_ISend(pp_data[dest], dest, MPI_TAG_MESH+1, comm)); + // req_per.Append(MyMPI_ISend(pp_data[dest], dest, MPI_TAG_MESH+1, comm)); + req_per.Append(comm.ISend(FlatArray(pp_data[dest]), dest, MPI_TAG_MESH+1)); MyMPI_WaitAll(req_per); PrintMessage ( 3, "Sending Vertices - distprocs"); diff --git a/libsrc/meshing/paralleltop.cpp b/libsrc/meshing/paralleltop.cpp index 06c08ab5..3fba9f87 100644 --- a/libsrc/meshing/paralleltop.cpp +++ b/libsrc/meshing/paralleltop.cpp @@ -122,7 +122,7 @@ namespace netgen *testout << "ParallelMeshTopology :: UpdateCoarseGridGlobal" << endl; const MeshTopology & topology = mesh.GetTopology(); - MPI_Comm comm = mesh.GetCommunicator(); + auto comm = mesh.GetCommunicator(); if ( id == 0 ) { @@ -160,7 +160,8 @@ namespace netgen Array sendrequests; for (int dest = 1; dest < ntasks; dest++) - sendrequests.Append (MyMPI_ISend (*sendarrays[dest], dest, MPI_TAG_MESH+10, comm)); + // sendrequests.Append (MyMPI_ISend (*sendarrays[dest], dest, MPI_TAG_MESH+10, comm)); + sendrequests.Append (comm.ISend (FlatArray(*sendarrays[dest]), dest, MPI_TAG_MESH+10)); MyMPI_WaitAll (sendrequests); for (int dest = 1; dest < ntasks; dest++) From 2e39d07cc834d32ab92d3cb80e03d34d2643984f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20Sch=C3=B6berl?= Date: Wed, 5 Aug 2020 18:05:31 +0200 Subject: [PATCH 102/384] mpi constants for non-mpi --- libsrc/core/mpi_wrapper.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libsrc/core/mpi_wrapper.hpp b/libsrc/core/mpi_wrapper.hpp index b2e32731..bf9540a5 100644 --- a/libsrc/core/mpi_wrapper.hpp +++ b/libsrc/core/mpi_wrapper.hpp @@ -314,9 +314,10 @@ namespace ngcore static MPI_Comm MPI_COMM_WORLD = 12345, MPI_COMM_NULL = 10000; typedef int MPI_Op; + typedef int MPI_Datatype; typedef int MPI_Request; - enum { MPI_SUM = 0, MPI_MIN = 1, MPI_MAX = 2 }; + enum { MPI_SUM = 0, MPI_MIN = 1, MPI_MAX = 2, MPI_LOR = 4711 }; class NgMPI_Comm { From 620b90fbee29a8a8e201e22ddfc272b2434cd980 Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Thu, 6 Aug 2020 18:06:26 +0200 Subject: [PATCH 103/384] read material names from fnf file --- libsrc/interface/read_fnf_mesh.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libsrc/interface/read_fnf_mesh.cpp b/libsrc/interface/read_fnf_mesh.cpp index 955a1356..2394f510 100644 --- a/libsrc/interface/read_fnf_mesh.cpp +++ b/libsrc/interface/read_fnf_mesh.cpp @@ -208,7 +208,9 @@ namespace netgen sbuf >> nr >> prop >> ch; if (prop == "DEF") { - ; + string name; + sbuf >> name; + mesh.SetMaterial(nr, name); } else { From acfe9bb6063a21739bfc8eaa47a9f99fb7f04f98 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Fri, 7 Aug 2020 12:01:49 +0200 Subject: [PATCH 104/384] Merge traces with MPI --- libsrc/core/paje_trace.cpp | 211 +++++++++++++++++++++++++++++++++--- libsrc/core/paje_trace.hpp | 2 + libsrc/core/taskmanager.cpp | 22 +--- 3 files changed, 202 insertions(+), 33 deletions(-) diff --git a/libsrc/core/paje_trace.cpp b/libsrc/core/paje_trace.cpp index 5c52a378..88601054 100644 --- a/libsrc/core/paje_trace.cpp +++ b/libsrc/core/paje_trace.cpp @@ -8,6 +8,7 @@ #include "archive.hpp" // for Demangle #include "paje_trace.hpp" #include "profiler.hpp" +#include "mpi_wrapper.hpp" extern const char *header; @@ -23,7 +24,6 @@ namespace ngcore PajeTrace :: PajeTrace(int anthreads, std::string aname) { - start_time = GetTimeCounter(); nthreads = anthreads; tracefile_name = std::move(aname); @@ -48,13 +48,40 @@ namespace ngcore jobs.reserve(reserve_size); timer_events.reserve(reserve_size); + // sync start time when running in parallel + NgMPI_Comm comm(MPI_COMM_WORLD); + for(auto i : Range(5)) + comm.Barrier(); + + start_time = GetTimeCounter(); tracing_enabled = true; } PajeTrace :: ~PajeTrace() { - if(!tracefile_name.empty()) + for(auto & ltask : tasks) + for(auto & task : ltask) + { + task.start_time -= start_time; + task.stop_time -= start_time; + } + for(auto & job : jobs) + { + job.start_time -= start_time; + job.stop_time -= start_time; + } + for(auto & event : timer_events) + event.time -= start_time; + + for(auto & llink : links) + for(auto & link : llink) + link.time -= start_time; + + NgMPI_Comm comm(MPI_COMM_WORLD); + if(comm.Rank() == 0) Write(tracefile_name); + else + SendData(); } @@ -90,7 +117,6 @@ namespace ngcore int alias_counter; FILE * ctrace_stream; - TTimePoint start_time; std::shared_ptr logger = GetLogger("PajeTrace"); @@ -98,7 +124,7 @@ namespace ngcore // return time in milliseconds as double // return std::chrono::duration(t-start_time).count()*1000.0; // return std::chrono::duration(t-start_time).count() / 2.7e3; - return 1000.0*static_cast(t-start_time) * seconds_per_tick; + return 1000.0*static_cast(t) * seconds_per_tick; } enum PType @@ -180,9 +206,8 @@ namespace ngcore void operator=(const PajeFile &) = delete; void operator=(PajeFile &&) = delete; - PajeFile( const std::string & filename, TTimePoint astart_time ) + PajeFile( const std::string & filename) { - start_time = astart_time; ctrace_stream = fopen (filename.c_str(),"w"); // NOLINT fprintf(ctrace_stream, "%s", header ); // NOLINT alias_counter = 0; @@ -365,7 +390,7 @@ namespace ngcore logger->warn("Tracing stopped during computation due to tracefile size limit of {} megabytes.", max_tracefile_size/1024/1024); } - PajeFile paje(filename, start_time); + PajeFile paje(filename); const int container_type_task_manager = paje.DefineContainerType( 0, "Task Manager" ); const int container_type_node = paje.DefineContainerType( container_type_task_manager, "Node"); @@ -381,16 +406,48 @@ namespace ngcore const int container_task_manager = paje.CreateContainer( container_type_task_manager, 0, "The task manager" ); const int container_jobs = paje.CreateContainer( container_type_jobs, container_task_manager, "Jobs" ); - paje.SetVariable( start_time, variable_type_active_threads, container_jobs, 0.0 ); - - const int num_nodes = 1; //task_manager ? task_manager->GetNumNodes() : 1; + paje.SetVariable( 0, variable_type_active_threads, container_jobs, 0.0 ); + int num_nodes = 1; //task_manager ? task_manager->GetNumNodes() : 1; + std::vector thread_aliases; std::vector container_nodes; + +#ifdef PARALLEL + // Hostnames + NgMPI_Comm comm(MPI_COMM_WORLD); + auto rank = comm.Rank(); + auto nranks = comm.Size(); + nthreads = nranks; + thread_aliases.reserve(nthreads); + + std::array ahostname; + int len; + MPI_Get_processor_name(ahostname.data(), &len); + std::string hostname = ahostname.data(); + + std::map host_map; + + host_map[hostname] = container_nodes.size(); + container_nodes.emplace_back( paje.CreateContainer( container_type_node, container_task_manager, hostname) ); + thread_aliases.emplace_back( paje.CreateContainer( container_type_thread, container_nodes[host_map[hostname]], "Rank 0" ) ); + + std::string name; + for(auto i : IntRange(1, nranks)) + { + comm.Recv(name, i, 0); + if(host_map.count(name)==0) + { + host_map[name] = container_nodes.size(); + container_nodes.emplace_back( paje.CreateContainer( container_type_node, container_task_manager, name) ); + } + thread_aliases.emplace_back( paje.CreateContainer( container_type_thread, container_nodes[host_map[name]], "Rank " + ToString(i) ) ); + } + +#else // PARALLEL container_nodes.reserve(num_nodes); for(int i=0; i thread_aliases; thread_aliases.reserve(nthreads); if(trace_threads) for (int i=0; i job_map; std::map job_task_map; @@ -418,18 +476,41 @@ namespace ngcore std::set timer_ids; std::map timer_aliases; + std::map timer_names; for(auto & event : timer_events) - timer_ids.insert(event.timer_id); + timer_ids.insert(event.timer_id); + // Timer names for(auto & vtasks : tasks) - for (Task & t : vtasks) - if(t.id_type==Task::ID_TIMER) - timer_ids.insert(t.id); + for (Task & t : vtasks) + if(t.id_type==Task::ID_TIMER) + timer_ids.insert(t.id); for(auto id : timer_ids) - timer_aliases[id] = paje.DefineEntityValue( state_type_timer, NgProfiler::GetName(id), -1 ); + timer_names[id] = NgProfiler::GetName(id); + +#ifdef PARALLEL + for(auto src : IntRange(1, nranks)) + { + size_t n_timers; + comm.Recv (n_timers, src, 0); + + int id; + std::string name; + for(auto i : IntRange(n_timers)) + { + comm.Recv (id, src, 0); + comm.Recv (name, src, 0); + timer_ids.insert(id); + timer_names[id] = name; + } + } +#endif // PARALLEL + + for(auto id : timer_ids) + timer_aliases[id] = paje.DefineEntityValue( state_type_timer, timer_names[id], -1 ); int timerdepth = 0; int maxdepth = 0; @@ -494,6 +575,44 @@ namespace ngcore } } +#ifdef PARALLEL + for(auto & event : timer_events) + { + if(event.is_start) + paje.PushState( event.time, state_type_timer, thread_aliases[0], timer_aliases[event.timer_id] ); + else + paje.PopState( event.time, state_type_timer, thread_aliases[0] ); + } + + // Timer events + Array timer_id; + Array time; + Array is_start; + Array thread_id; + + for(auto src : IntRange(1, nranks)) + { + comm.Recv (timer_id, src, 0); + comm.Recv (time, src, 0); + comm.Recv (is_start, src, 0); + comm.Recv (thread_id, src, 0); + + for(auto i : Range(timer_id.Size())) + { + TimerEvent event; + event.timer_id = timer_id[i]; + event.time = time[i]; + event.is_start = is_start[i]; + event.thread_id = thread_id[i]; + + if(event.is_start) + paje.PushState( event.time, state_type_timer, thread_aliases[src], timer_aliases[event.timer_id] ); + else + paje.PopState( event.time, state_type_timer, thread_aliases[src] ); + } + } +#endif // PARALLEL + // Merge link event int nlinks = 0; for( auto & l : links) @@ -556,6 +675,66 @@ namespace ngcore paje.WriteEvents(); } + void PajeTrace::SendData( ) + { +#ifdef PARALLEL + // Hostname + NgMPI_Comm comm(MPI_COMM_WORLD); + auto rank = comm.Rank(); + auto nranks = comm.Size(); + + std::string hostname; + { + std::array ahostname; + int len; + MPI_Get_processor_name(ahostname.data(), &len); + hostname = ahostname.data(); + } + + comm.Send(hostname, 0, 0); + + // Timer names + std::set timer_ids; + std::map timer_names; + + for(auto & event : timer_events) + { + event.timer_id += NgProfiler::SIZE*rank; + timer_ids.insert(event.timer_id); + } + + for(auto id : timer_ids) + timer_names[id] = NgProfiler::GetName(id-NgProfiler::SIZE*rank); + size_t size = timer_ids.size(); + comm.Send(size, 0, 0); + for(auto id : timer_ids) + { + comm.Send(id, 0, 0); + comm.Send(timer_names[id], 0, 0); + } + + + // Timer events + Array timer_id; + Array time; + Array is_start; + Array thread_id; + + for(auto & event : timer_events) + { + timer_id.Append(event.timer_id); + time.Append(event.time); + is_start.Append(event.is_start); + thread_id.Append(event.thread_id); + } + + comm.Send (timer_id, 0, 0); + comm.Send (time, 0, 0); + comm.Send (is_start, 0, 0); + comm.Send (thread_id, 0, 0); +#endif // PARALLEL + } + /////////////////////////////////////////////////////////////////// // Write HTML file drawing a sunburst chart with cumulated timings struct TreeNode diff --git a/libsrc/core/paje_trace.hpp b/libsrc/core/paje_trace.hpp index 1d656ca3..95c42d4a 100644 --- a/libsrc/core/paje_trace.hpp +++ b/libsrc/core/paje_trace.hpp @@ -185,6 +185,8 @@ namespace ngcore void Write( const std::string & filename ); + void SendData(); // MPI parallel data reduction + }; } // namespace ngcore diff --git a/libsrc/core/taskmanager.cpp b/libsrc/core/taskmanager.cpp index e730e55c..ef38a277 100644 --- a/libsrc/core/taskmanager.cpp +++ b/libsrc/core/taskmanager.cpp @@ -159,22 +159,8 @@ namespace ngcore active_workers = 0; static int cnt = 0; - char buf[100]; if (use_paje_trace) - { -#ifdef PARALLEL - int is_init = -1; - MPI_Initialized(&is_init); - if (is_init) - sprintf(buf, "ng%d_rank%d.trace", cnt++, NgMPI_Comm(MPI_COMM_WORLD).Rank()); - else -#endif - sprintf(buf, "ng%d.trace", cnt++); - } - else - buf[0] = 0; - //sprintf(buf, ""); - trace = new PajeTrace(num_threads, buf); + trace = new PajeTrace(num_threads, "ng" + ToString(cnt++) + ".trace"); } @@ -349,7 +335,8 @@ namespace ngcore } - trace->StartJob(jobnr, afunc.target_type()); + if (use_paje_trace) + trace->StartJob(jobnr, afunc.target_type()); func = &afunc; @@ -419,7 +406,8 @@ namespace ngcore if (ex) throw Exception (*ex); - trace->StopJob(); + if (use_paje_trace) + trace->StopJob(); } void TaskManager :: Loop(int thd) From f9ff1db7c3349688779371de8feddf9294af5495 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Fri, 7 Aug 2020 15:34:21 +0200 Subject: [PATCH 105/384] let MPI rank 1 write paje trace file (more timers than rank0) --- libsrc/core/paje_trace.cpp | 45 ++++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/libsrc/core/paje_trace.cpp b/libsrc/core/paje_trace.cpp index 88601054..421cb0c7 100644 --- a/libsrc/core/paje_trace.cpp +++ b/libsrc/core/paje_trace.cpp @@ -12,6 +12,8 @@ extern const char *header; +constexpr int MPI_PAJE_WRITER = 1; + namespace ngcore { // Produce no traces by default @@ -78,7 +80,7 @@ namespace ngcore link.time -= start_time; NgMPI_Comm comm(MPI_COMM_WORLD); - if(comm.Rank() == 0) + if(comm.Size()==1 || comm.Rank() == MPI_PAJE_WRITER) Write(tracefile_name); else SendData(); @@ -427,14 +429,13 @@ namespace ngcore std::map host_map; - host_map[hostname] = container_nodes.size(); - container_nodes.emplace_back( paje.CreateContainer( container_type_node, container_task_manager, hostname) ); - thread_aliases.emplace_back( paje.CreateContainer( container_type_thread, container_nodes[host_map[hostname]], "Rank 0" ) ); - std::string name; - for(auto i : IntRange(1, nranks)) + for(auto i : IntRange(0, nranks)) { - comm.Recv(name, i, 0); + if(i!=MPI_PAJE_WRITER) + comm.Recv(name, i, 0); + else + name = hostname; if(host_map.count(name)==0) { host_map[name] = container_nodes.size(); @@ -492,8 +493,11 @@ namespace ngcore timer_names[id] = NgProfiler::GetName(id); #ifdef PARALLEL - for(auto src : IntRange(1, nranks)) + for(auto src : IntRange(0, nranks)) { + if(src==MPI_PAJE_WRITER) + continue; + size_t n_timers; comm.Recv (n_timers, src, 0); @@ -579,9 +583,9 @@ namespace ngcore for(auto & event : timer_events) { if(event.is_start) - paje.PushState( event.time, state_type_timer, thread_aliases[0], timer_aliases[event.timer_id] ); + paje.PushState( event.time, state_type_timer, thread_aliases[MPI_PAJE_WRITER], timer_aliases[event.timer_id] ); else - paje.PopState( event.time, state_type_timer, thread_aliases[0] ); + paje.PopState( event.time, state_type_timer, thread_aliases[MPI_PAJE_WRITER] ); } // Timer events @@ -590,8 +594,11 @@ namespace ngcore Array is_start; Array thread_id; - for(auto src : IntRange(1, nranks)) + for(auto src : IntRange(0, nranks)) { + if(src==MPI_PAJE_WRITER) + continue; + comm.Recv (timer_id, src, 0); comm.Recv (time, src, 0); comm.Recv (is_start, src, 0); @@ -691,7 +698,7 @@ namespace ngcore hostname = ahostname.data(); } - comm.Send(hostname, 0, 0); + comm.Send(hostname, MPI_PAJE_WRITER, 0); // Timer names std::set timer_ids; @@ -706,11 +713,11 @@ namespace ngcore for(auto id : timer_ids) timer_names[id] = NgProfiler::GetName(id-NgProfiler::SIZE*rank); size_t size = timer_ids.size(); - comm.Send(size, 0, 0); + comm.Send(size, MPI_PAJE_WRITER, 0); for(auto id : timer_ids) { - comm.Send(id, 0, 0); - comm.Send(timer_names[id], 0, 0); + comm.Send(id, MPI_PAJE_WRITER, 0); + comm.Send(timer_names[id], MPI_PAJE_WRITER, 0); } @@ -728,10 +735,10 @@ namespace ngcore thread_id.Append(event.thread_id); } - comm.Send (timer_id, 0, 0); - comm.Send (time, 0, 0); - comm.Send (is_start, 0, 0); - comm.Send (thread_id, 0, 0); + comm.Send (timer_id, MPI_PAJE_WRITER, 0); + comm.Send (time, MPI_PAJE_WRITER, 0); + comm.Send (is_start, MPI_PAJE_WRITER, 0); + comm.Send (thread_id, MPI_PAJE_WRITER, 0); #endif // PARALLEL } From b272614a5158fda25e00babc4cb0da2045372c0e Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Fri, 7 Aug 2020 15:34:47 +0200 Subject: [PATCH 106/384] export PajeTrace to Python (with context manager api) --- libsrc/core/python_ngcore_export.cpp | 21 +++++++++++++++++++++ libsrc/core/taskmanager.cpp | 11 +++++++---- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/libsrc/core/python_ngcore_export.cpp b/libsrc/core/python_ngcore_export.cpp index 1aaf12b0..4f93168e 100644 --- a/libsrc/core/python_ngcore_export.cpp +++ b/libsrc/core/python_ngcore_export.cpp @@ -246,4 +246,25 @@ threads : int .def("__timing__", &TaskManager::Timing) ; + py::class_(m, "PajeTrace") + .def(py::init( [] (string filename, size_t size_mb, bool threads, bool thread_counter) + { + PajeTrace::SetMaxTracefileSize(size_mb*1014*1024); + PajeTrace::SetTraceThreads(threads); + 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, + "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) + ; + + } diff --git a/libsrc/core/taskmanager.cpp b/libsrc/core/taskmanager.cpp index ef38a277..4a49adff 100644 --- a/libsrc/core/taskmanager.cpp +++ b/libsrc/core/taskmanager.cpp @@ -166,8 +166,11 @@ namespace ngcore TaskManager :: ~TaskManager () { - delete trace; - trace = nullptr; + if (use_paje_trace) + { + delete trace; + trace = nullptr; + } num_threads = 1; } @@ -335,7 +338,7 @@ namespace ngcore } - if (use_paje_trace) + if (trace) trace->StartJob(jobnr, afunc.target_type()); func = &afunc; @@ -406,7 +409,7 @@ namespace ngcore if (ex) throw Exception (*ex); - if (use_paje_trace) + if (trace) trace->StopJob(); } From 87c2901e325f28bdc7a3ad64f64e5f6ed3028610 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Fri, 7 Aug 2020 15:44:21 +0200 Subject: [PATCH 107/384] Disable paje trace thread counter by default (halves trace file size) --- libsrc/core/paje_trace.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/libsrc/core/paje_trace.cpp b/libsrc/core/paje_trace.cpp index 421cb0c7..eaae23a1 100644 --- a/libsrc/core/paje_trace.cpp +++ b/libsrc/core/paje_trace.cpp @@ -21,7 +21,7 @@ namespace ngcore // If true, produce variable counting active threads // increases trace by a factor of two - bool PajeTrace::trace_thread_counter = true; + bool PajeTrace::trace_thread_counter = false; bool PajeTrace::trace_threads = true; PajeTrace :: PajeTrace(int anthreads, std::string aname) @@ -31,7 +31,7 @@ namespace ngcore tracefile_name = std::move(aname); int bytes_per_event=33; - max_num_events_per_thread = std::min( static_cast(std::numeric_limits::max()), max_tracefile_size/bytes_per_event/(2*nthreads+1)*10/7); + max_num_events_per_thread = std::min( static_cast(std::numeric_limits::max()), max_tracefile_size/bytes_per_event/(nthreads+1+trace_thread_counter*nthreads)*10/7); if(max_num_events_per_thread>0) { logger->info( "Tracefile size = {}MB", max_tracefile_size/1024/1024); @@ -404,11 +404,14 @@ namespace ngcore const int state_type_task = paje.DefineStateType( container_type_thread, "Task" ); const int state_type_timer = paje.DefineStateType( container_type_timer, "Timer state" ); - const int variable_type_active_threads = paje.DefineVariableType( container_type_jobs, "Active threads" ); + int variable_type_active_threads = 0; + if(trace_thread_counter) + paje.DefineVariableType( container_type_jobs, "Active threads" ); const int container_task_manager = paje.CreateContainer( container_type_task_manager, 0, "The task manager" ); const int container_jobs = paje.CreateContainer( container_type_jobs, container_task_manager, "Jobs" ); - paje.SetVariable( 0, variable_type_active_threads, container_jobs, 0.0 ); + if(trace_thread_counter) + paje.SetVariable( 0, variable_type_active_threads, container_jobs, 0.0 ); int num_nodes = 1; //task_manager ? task_manager->GetNumNodes() : 1; std::vector thread_aliases; From 72447a51d5e97f6d00b33772a0a23a67a10760a3 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Mon, 10 Aug 2020 12:20:17 +0200 Subject: [PATCH 108/384] Fix paje trace with MPI and TaskManager --- libsrc/core/paje_trace.cpp | 112 ++++++++++++++++++++----------------- 1 file changed, 61 insertions(+), 51 deletions(-) diff --git a/libsrc/core/paje_trace.cpp b/libsrc/core/paje_trace.cpp index eaae23a1..4787d213 100644 --- a/libsrc/core/paje_trace.cpp +++ b/libsrc/core/paje_trace.cpp @@ -422,44 +422,48 @@ namespace ngcore NgMPI_Comm comm(MPI_COMM_WORLD); auto rank = comm.Rank(); auto nranks = comm.Size(); - nthreads = nranks; - thread_aliases.reserve(nthreads); + if(nranks>1) + { + nthreads = nranks; + thread_aliases.reserve(nthreads); - std::array ahostname; - int len; - MPI_Get_processor_name(ahostname.data(), &len); - std::string hostname = ahostname.data(); + std::array ahostname; + int len; + MPI_Get_processor_name(ahostname.data(), &len); + std::string hostname = ahostname.data(); - std::map host_map; + std::map host_map; - std::string name; - for(auto i : IntRange(0, nranks)) + std::string name; + for(auto i : IntRange(0, nranks)) { if(i!=MPI_PAJE_WRITER) - comm.Recv(name, i, 0); + comm.Recv(name, i, 0); else - name = hostname; + name = hostname; if(host_map.count(name)==0) - { - host_map[name] = container_nodes.size(); - container_nodes.emplace_back( paje.CreateContainer( container_type_node, container_task_manager, name) ); - } + { + host_map[name] = container_nodes.size(); + container_nodes.emplace_back( paje.CreateContainer( container_type_node, container_task_manager, name) ); + } thread_aliases.emplace_back( paje.CreateContainer( container_type_thread, container_nodes[host_map[name]], "Rank " + ToString(i) ) ); } - -#else // PARALLEL - container_nodes.reserve(num_nodes); - for(int i=0; i job_map; std::map job_task_map; @@ -496,10 +500,12 @@ namespace ngcore timer_names[id] = NgProfiler::GetName(id); #ifdef PARALLEL - for(auto src : IntRange(0, nranks)) + if(nranks>1) + { + for(auto src : IntRange(0, nranks)) { if(src==MPI_PAJE_WRITER) - continue; + continue; size_t n_timers; comm.Recv (n_timers, src, 0); @@ -507,13 +513,14 @@ namespace ngcore int id; std::string name; for(auto i : IntRange(n_timers)) - { - comm.Recv (id, src, 0); - comm.Recv (name, src, 0); - timer_ids.insert(id); - timer_names[id] = name; - } + { + comm.Recv (id, src, 0); + comm.Recv (name, src, 0); + timer_ids.insert(id); + timer_names[id] = name; + } } + } #endif // PARALLEL for(auto id : timer_ids) @@ -583,7 +590,9 @@ namespace ngcore } #ifdef PARALLEL - for(auto & event : timer_events) + if(nranks>1) + { + for(auto & event : timer_events) { if(event.is_start) paje.PushState( event.time, state_type_timer, thread_aliases[MPI_PAJE_WRITER], timer_aliases[event.timer_id] ); @@ -591,16 +600,16 @@ namespace ngcore paje.PopState( event.time, state_type_timer, thread_aliases[MPI_PAJE_WRITER] ); } - // Timer events - Array timer_id; - Array time; - Array is_start; - Array thread_id; + // Timer events + Array timer_id; + Array time; + Array is_start; + Array thread_id; - for(auto src : IntRange(0, nranks)) + for(auto src : IntRange(0, nranks)) { if(src==MPI_PAJE_WRITER) - continue; + continue; comm.Recv (timer_id, src, 0); comm.Recv (time, src, 0); @@ -608,19 +617,20 @@ namespace ngcore comm.Recv (thread_id, src, 0); for(auto i : Range(timer_id.Size())) - { - TimerEvent event; - event.timer_id = timer_id[i]; - event.time = time[i]; - event.is_start = is_start[i]; - event.thread_id = thread_id[i]; + { + TimerEvent event; + event.timer_id = timer_id[i]; + event.time = time[i]; + event.is_start = is_start[i]; + event.thread_id = thread_id[i]; - if(event.is_start) - paje.PushState( event.time, state_type_timer, thread_aliases[src], timer_aliases[event.timer_id] ); - else - paje.PopState( event.time, state_type_timer, thread_aliases[src] ); - } + if(event.is_start) + paje.PushState( event.time, state_type_timer, thread_aliases[src], timer_aliases[event.timer_id] ); + else + paje.PopState( event.time, state_type_timer, thread_aliases[src] ); + } } + } #endif // PARALLEL // Merge link event @@ -818,7 +828,7 @@ namespace ngcore std::sort (events.begin(), events.end()); - root.time = 1000.0*static_cast(stop_time-start_time) * seconds_per_tick; + root.time = 1000.0*static_cast(stop_time) * seconds_per_tick; for(auto & event : events) { From 0fefe5d32c44f54afcfd25e4ac879304dad5985e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20Sch=C3=B6berl?= Date: Mon, 10 Aug 2020 16:44:14 +0200 Subject: [PATCH 109/384] timers in Netgen --- libsrc/meshing/meshclass.cpp | 1 + libsrc/meshing/paralleltop.cpp | 1 + libsrc/meshing/refine.cpp | 2 ++ 3 files changed, 4 insertions(+) diff --git a/libsrc/meshing/meshclass.cpp b/libsrc/meshing/meshclass.cpp index ea30e5f6..2eacb717 100644 --- a/libsrc/meshing/meshclass.cpp +++ b/libsrc/meshing/meshclass.cpp @@ -6420,6 +6420,7 @@ namespace netgen void Mesh :: UpdateTopology (TaskManager tm, Tracer tracer) { + static Timer t("Update Topology"); RegionTimer reg(t); topology.Update(tm, tracer); (*tracer)("call update clusters", false); clusters->Update(tm, tracer); diff --git a/libsrc/meshing/paralleltop.cpp b/libsrc/meshing/paralleltop.cpp index 3fba9f87..9e07fd73 100644 --- a/libsrc/meshing/paralleltop.cpp +++ b/libsrc/meshing/paralleltop.cpp @@ -207,6 +207,7 @@ namespace netgen void ParallelMeshTopology :: UpdateCoarseGrid () { + static Timer t("ParallelTopology::UpdateCoarseGrid"); RegionTimer r(t); // cout << "UpdateCoarseGrid" << endl; // if (is_updated) return; diff --git a/libsrc/meshing/refine.cpp b/libsrc/meshing/refine.cpp index bc4a2e5b..6f9e4585 100644 --- a/libsrc/meshing/refine.cpp +++ b/libsrc/meshing/refine.cpp @@ -15,7 +15,9 @@ namespace netgen { if (mesh.GetCommunicator().Rank()==0) PrintMessage (3, "Refine mesh"); + Timer t("Refine mesh"); RegionTimer reg(t); + mesh.SetNextMajorTimeStamp(); if (ntasks > 1 && id == 0) From a0f70b4d73970ec1139f6727f54308ab940ceb29 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Thu, 13 Aug 2020 19:52:55 +0200 Subject: [PATCH 110/384] SplineSeg3 ctor with custom weight --- libsrc/gprim/spline.cpp | 10 ++++++++++ libsrc/gprim/spline.hpp | 4 ++++ 2 files changed, 14 insertions(+) diff --git a/libsrc/gprim/spline.cpp b/libsrc/gprim/spline.cpp index a2778d91..4a17da71 100644 --- a/libsrc/gprim/spline.cpp +++ b/libsrc/gprim/spline.cpp @@ -98,6 +98,16 @@ namespace netgen proj_latest_t = 0.5; } + template + SplineSeg3 :: SplineSeg3 (const GeomPoint & ap1, + const GeomPoint & ap2, + const GeomPoint & ap3, + double aweight) + : p1(ap1), p2(ap2), p3(ap3), weight(aweight) + { + proj_latest_t = 0.5; + } + template Point SplineSeg3 :: GetPoint (double t) const { diff --git a/libsrc/gprim/spline.hpp b/libsrc/gprim/spline.hpp index 6549587d..d2ba6f4e 100644 --- a/libsrc/gprim/spline.hpp +++ b/libsrc/gprim/spline.hpp @@ -185,6 +185,10 @@ namespace netgen SplineSeg3 (const GeomPoint & ap1, const GeomPoint & ap2, const GeomPoint & ap3); + SplineSeg3 (const GeomPoint & ap1, + const GeomPoint & ap2, + const GeomPoint & ap3, + double aweight); // default constructor for archive SplineSeg3() {} /// From 33626c666996d9dd8c520cd06a819029d0d7e4d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20Sch=C3=B6berl?= Date: Mon, 17 Aug 2020 15:55:15 +0200 Subject: [PATCH 111/384] clear solutiondata object on python-exit --- libsrc/core/python_ngcore.hpp | 8 +++++ libsrc/general/parthreads.hpp | 8 ++--- libsrc/interface/nginterface_v2.cpp | 2 +- libsrc/meshing/bisect.cpp | 4 +-- libsrc/meshing/bisect.hpp | 4 +-- libsrc/meshing/clusters.cpp | 2 +- libsrc/meshing/clusters.hpp | 2 +- libsrc/meshing/meshclass.cpp | 8 +++-- libsrc/meshing/meshclass.hpp | 4 +-- libsrc/meshing/python_mesh.cpp | 13 ++++++++ libsrc/meshing/topology.cpp | 50 +++++++++++++++++------------ libsrc/meshing/topology.hpp | 2 +- python/__init__.py | 2 ++ python/meshing.py | 3 ++ 14 files changed, 75 insertions(+), 37 deletions(-) diff --git a/libsrc/core/python_ngcore.hpp b/libsrc/core/python_ngcore.hpp index 6bedabf9..a089c5e8 100644 --- a/libsrc/core/python_ngcore.hpp +++ b/libsrc/core/python_ngcore.hpp @@ -11,6 +11,7 @@ #include "archive.hpp" #include "flags.hpp" #include "ngcore_api.hpp" +#include "profiler.hpp" namespace py = pybind11; namespace ngcore @@ -297,18 +298,25 @@ namespace ngcore { PyArchive ar; ar & self; + static Timer t("ngspickle 2"); + t.Start(); auto output = pybind11::make_tuple(ar.WriteOut()); + t.Stop(); + /* GetLogger("Archive")->trace("Pickling output for object of type {} = {}", Demangle(typeid(T).name()), std::string(pybind11::str(output))); + */ return output; }, [](const pybind11::tuple & state) { T* val = nullptr; + /* GetLogger("Archive")->trace("State for unpickling of object of type {} = {}", Demangle(typeid(T).name()), std::string(pybind11::str(state[0]))); + */ PyArchive ar(state[0]); ar & val; return val; diff --git a/libsrc/general/parthreads.hpp b/libsrc/general/parthreads.hpp index 2e242484..d7f42a4a 100644 --- a/libsrc/general/parthreads.hpp +++ b/libsrc/general/parthreads.hpp @@ -96,8 +96,8 @@ void ParallelFor( int first, int next, const TFunc & f ) - typedef void (*TaskManager)(std::function); - typedef void (*Tracer)(string, bool); // false .. start, true .. stop + typedef void (*NgTaskManager)(std::function); + typedef void (*NgTracer)(string, bool); // false .. start, true .. stop inline void DummyTaskManager (std::function func) { @@ -108,7 +108,7 @@ void ParallelFor( int first, int next, const TFunc & f ) inline void DummyTracer (string, bool) { ; } template - inline void ParallelFor (TaskManager tm, size_t n, FUNC func) + inline void ParallelFor (NgTaskManager tm, size_t n, FUNC func) { (*tm) ([n,func] (size_t nr, size_t nums) { @@ -121,7 +121,7 @@ void ParallelFor( int first, int next, const TFunc & f ) } template - inline void ParallelForRange (TaskManager tm, size_t n, FUNC func) + inline void ParallelForRange (NgTaskManager tm, size_t n, FUNC func) { (*tm) ([n,func] (size_t nr, size_t nums) { diff --git a/libsrc/interface/nginterface_v2.cpp b/libsrc/interface/nginterface_v2.cpp index e06d83eb..e2501ab4 100644 --- a/libsrc/interface/nginterface_v2.cpp +++ b/libsrc/interface/nginterface_v2.cpp @@ -1157,7 +1157,7 @@ namespace netgen void Ngx_Mesh :: Refine (NG_REFINEMENT_TYPE reftype, void (*task_manager)(function), - Tracer tracer) + NgTracer tracer) { NgLock meshlock (mesh->MajorMutex(), 1); diff --git a/libsrc/meshing/bisect.cpp b/libsrc/meshing/bisect.cpp index 9b5c770f..1f9bbba8 100644 --- a/libsrc/meshing/bisect.cpp +++ b/libsrc/meshing/bisect.cpp @@ -1681,7 +1681,7 @@ namespace netgen int MarkHangingTets (T_MTETS & mtets, const INDEX_2_CLOSED_HASHTABLE & cutedges, - TaskManager tm) + NgTaskManager tm) { static int timer = NgProfiler::CreateTimer ("MarkHangingTets"); NgProfiler::RegionTimer reg (timer); @@ -1759,7 +1759,7 @@ namespace netgen bool MarkHangingTris (T_MTRIS & mtris, const INDEX_2_CLOSED_HASHTABLE & cutedges, - TaskManager tm) + NgTaskManager tm) { bool hanging = false; // for (int i = 1; i <= mtris.Size(); i++) diff --git a/libsrc/meshing/bisect.hpp b/libsrc/meshing/bisect.hpp index 6b96bd07..16849227 100644 --- a/libsrc/meshing/bisect.hpp +++ b/libsrc/meshing/bisect.hpp @@ -12,8 +12,8 @@ public: int usemarkedelements; bool refine_hp; bool refine_p; - TaskManager task_manager = &DummyTaskManager; - Tracer tracer = &DummyTracer; + NgTaskManager task_manager = &DummyTaskManager; + NgTracer tracer = &DummyTracer; DLL_HEADER BisectionOptions (); }; diff --git a/libsrc/meshing/clusters.cpp b/libsrc/meshing/clusters.cpp index dafe81f8..dae820df 100644 --- a/libsrc/meshing/clusters.cpp +++ b/libsrc/meshing/clusters.cpp @@ -16,7 +16,7 @@ namespace netgen ; } - void AnisotropicClusters :: Update(TaskManager tm, Tracer tracer) + void AnisotropicClusters :: Update(NgTaskManager tm, NgTracer tracer) { static int timer = NgProfiler::CreateTimer ("clusters"); // static int timer1 = NgProfiler::CreateTimer ("clusters1"); diff --git a/libsrc/meshing/clusters.hpp b/libsrc/meshing/clusters.hpp index bf9a5a56..21e122fb 100644 --- a/libsrc/meshing/clusters.hpp +++ b/libsrc/meshing/clusters.hpp @@ -27,7 +27,7 @@ public: AnisotropicClusters (const Mesh & amesh); ~AnisotropicClusters(); - void Update(TaskManager tm = &DummyTaskManager, Tracer trace = &DummyTracer); + void Update(NgTaskManager tm = &DummyTaskManager, NgTracer trace = &DummyTracer); int GetVertexRepresentant (int vnr) const { return cluster_reps.Get(vnr); } diff --git a/libsrc/meshing/meshclass.cpp b/libsrc/meshing/meshclass.cpp index 2eacb717..5229f5d2 100644 --- a/libsrc/meshing/meshclass.cpp +++ b/libsrc/meshing/meshclass.cpp @@ -1280,10 +1280,14 @@ namespace netgen void Mesh :: DoArchive (Archive & archive) { + static Timer t("Mesh::Archive"); RegionTimer r(t); + static Timer tvol("Mesh::Archive vol elements"); archive & dimension; archive & points; archive & surfelements; + tvol.Start(); archive & volelements; + tvol.Stop(); archive & segments; archive & facedecoding; archive & materials & bcnames & cd2names & cd3names; @@ -6417,8 +6421,8 @@ namespace netgen return 1; } - void Mesh :: UpdateTopology (TaskManager tm, - Tracer tracer) + void Mesh :: UpdateTopology (NgTaskManager tm, + NgTracer tracer) { static Timer t("Update Topology"); RegionTimer reg(t); topology.Update(tm, tracer); diff --git a/libsrc/meshing/meshclass.hpp b/libsrc/meshing/meshclass.hpp index 4ff21ae8..5139cb8c 100644 --- a/libsrc/meshing/meshclass.hpp +++ b/libsrc/meshing/meshclass.hpp @@ -777,8 +777,8 @@ namespace netgen const MeshTopology & GetTopology () const { return topology; } - DLL_HEADER void UpdateTopology (TaskManager tm = &DummyTaskManager, - Tracer tracer = &DummyTracer); + DLL_HEADER void UpdateTopology (NgTaskManager tm = &DummyTaskManager, + NgTracer tracer = &DummyTracer); class CurvedElements & GetCurvedElements () const { return *curvedelems; } diff --git a/libsrc/meshing/python_mesh.cpp b/libsrc/meshing/python_mesh.cpp index a7edcec5..0d0877b0 100644 --- a/libsrc/meshing/python_mesh.cpp +++ b/libsrc/meshing/python_mesh.cpp @@ -11,6 +11,15 @@ // #include // #include #include <../interface/writeuser.hpp> +#include <../include/nginterface.h> + + +class ClearSolutionClass +{ +public: + ClearSolutionClass() { } + ~ClearSolutionClass() { Ng_ClearSolutionData(); } +}; #ifdef NG_MPI4PY @@ -1238,6 +1247,10 @@ grow_edges : bool = False }, py::arg("quads")=true, py::arg("nx")=10, py::arg("ny")=10, py::arg("flip_triangles")=false, py::arg("bbbpts")=py::list(), py::arg("bbbnames")=py::list()) ; ; + + py::class_ (m, "ClearSolutionClass") + .def(py::init<>()) + ; } PYBIND11_MODULE(libmesh, m) { diff --git a/libsrc/meshing/topology.cpp b/libsrc/meshing/topology.cpp index 6fd54b8b..65dca902 100644 --- a/libsrc/meshing/topology.cpp +++ b/libsrc/meshing/topology.cpp @@ -3,7 +3,8 @@ namespace netgen { - + using ngcore::ParallelForRange; + template void QuickSortRec (NgFlatArray data, @@ -332,10 +333,10 @@ namespace netgen } - void MeshTopology :: Update (TaskManager tm, Tracer tracer) + void MeshTopology :: Update (NgTaskManager tm_unused, NgTracer tracer) { - static int timer = NgProfiler::CreateTimer ("topology"); - NgProfiler::RegionTimer reg (timer); + static Timer timer("Topology::Update"); + RegionTimer reg (timer); #ifdef PARALLEL // ParallelMeshTopology & paralleltop = mesh.GetParallelTopology(); @@ -382,10 +383,9 @@ namespace netgen } */ ParallelForRange - (tm, ne, - [&] (size_t begin, size_t end) + (ne, [&] (IntRange r) { - for (ElementIndex ei = begin; ei < end; ei++) + for (ElementIndex ei : r) { const Element & el = (*mesh)[ei]; for (int j = 0; j < el.GetNV(); j++) @@ -426,10 +426,10 @@ namespace netgen } */ ParallelForRange - (tm, nse, - [&] (size_t begin, size_t end) + (nse, + [&] (IntRange r) { - for (SurfaceElementIndex ei = begin; ei < end; ei++) + for (SurfaceElementIndex ei : r) { const Element2d & el = (*mesh)[ei]; for (int j = 0; j < el.GetNV(); j++) @@ -553,9 +553,11 @@ namespace netgen cnt = 0; ParallelForRange - (tm, mesh->GetNV(), // Points().Size(), - [&] (size_t begin, size_t end) + (mesh->GetNV(), // Points().Size(), + [&] (IntRange r) { + auto begin = r.First(); + auto end = r.Next(); INDEX_CLOSED_HASHTABLE v2eht(2*max_edge_on_vertex+10); for (PointIndex v = begin+PointIndex::BASE; v < end+PointIndex::BASE; v++) @@ -607,9 +609,11 @@ namespace netgen // for (PointIndex v = PointIndex::BASE; v < nv+PointIndex::BASE; v++) ParallelForRange - (tm, mesh->GetNV(), // Points().Size(), - [&] (size_t begin, size_t end) + (mesh->GetNV(), // Points().Size(), + [&] (IntRange r) { + auto begin = r.First(); + auto end = r.Next(); INDEX_CLOSED_HASHTABLE v2eht(2*max_edge_on_vertex+10); NgArray vertex2; for (PointIndex v = begin+PointIndex::BASE; @@ -731,9 +735,11 @@ namespace netgen // for (auto v : mesh.Points().Range()) // NgProfiler::StartTimer (timer2b1); ParallelForRange - (tm, mesh->GetNV(), // Points().Size(), - [&] (size_t begin, size_t end) + (mesh->GetNV(), // Points().Size(), + [&] (IntRange r) { + auto begin = r.First(); + auto end = r.Next(); INDEX_3_CLOSED_HASHTABLE vert2face(2*max_face_on_vertex+10); for (PointIndex v = begin+PointIndex::BASE; v < end+PointIndex::BASE; v++) @@ -779,9 +785,11 @@ namespace netgen // for (auto v : mesh.Points().Range()) ParallelForRange - (tm, mesh->GetNV(), // Points().Size(), - [&] (size_t begin, size_t end) + (mesh->GetNV(), // Points().Size(), + [&] (IntRange r) { + auto begin = r.First(); + auto end = r.Next(); INDEX_3_CLOSED_HASHTABLE vert2face(2*max_face_on_vertex+10); for (PointIndex v = begin+PointIndex::BASE; v < end+PointIndex::BASE; v++) @@ -1164,11 +1172,11 @@ namespace netgen } */ ParallelForRange - (tm, ne, - [&] (size_t begin, size_t end) + (ne, + [&] (IntRange r) { NgArray hfaces; - for (ElementIndex ei = begin; ei < end; ei++) + for (ElementIndex ei : r) { GetElementFaces (ei+1, hfaces); for (auto f : hfaces) diff --git a/libsrc/meshing/topology.hpp b/libsrc/meshing/topology.hpp index 8335f101..00f599f6 100644 --- a/libsrc/meshing/topology.hpp +++ b/libsrc/meshing/topology.hpp @@ -81,7 +81,7 @@ public: bool HasFaces () const { return buildfaces; } - void Update(TaskManager tm = &DummyTaskManager, Tracer tracer = &DummyTracer); + void Update(NgTaskManager tm = &DummyTaskManager, NgTracer tracer = &DummyTracer); bool NeedsUpdate() const; diff --git a/python/__init__.py b/python/__init__.py index e7c23d66..17dbdbe1 100644 --- a/python/__init__.py +++ b/python/__init__.py @@ -22,3 +22,5 @@ def Redraw(*args, **kwargs): cnt += 1 except: pass + + diff --git a/python/meshing.py b/python/meshing.py index 788f248a..9b912b66 100644 --- a/python/meshing.py +++ b/python/meshing.py @@ -59,3 +59,6 @@ class _MeshsizeObject: optsteps3d=5) meshsize = _MeshsizeObject() + + +clearsol = ClearSolutionClass() From 9e105c48ea87bf90f8e57ba9c4520ab817be46e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20Sch=C3=B6berl?= Date: Mon, 17 Aug 2020 20:28:00 +0200 Subject: [PATCH 112/384] mpi-wrapper --- libsrc/core/mpi_wrapper.hpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/libsrc/core/mpi_wrapper.hpp b/libsrc/core/mpi_wrapper.hpp index bf9540a5..8d9631f5 100644 --- a/libsrc/core/mpi_wrapper.hpp +++ b/libsrc/core/mpi_wrapper.hpp @@ -275,6 +275,18 @@ namespace ngcore &recv, 1, GetMPIType(), 0, comm); } + template + void AllGather (T val, FlatArray recv) const + { + if (size == 1) + { + recv[0] = val; + return; + } + MPI_Allgather (&val, 1, GetMPIType(), + recv.Data(), 1, GetMPIType(), + comm); + } NgMPI_Comm SubCommunicator (FlatArray procs) const From 5e0962646636819a14aa8166701fde7842a57701 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20Sch=C3=B6berl?= Date: Wed, 19 Aug 2020 14:50:11 +0200 Subject: [PATCH 113/384] parallel pickling with mesh-merging --- libsrc/core/archive.hpp | 4 + libsrc/core/array.hpp | 2 +- libsrc/core/mpi_wrapper.hpp | 19 +++-- libsrc/core/python_ngcore.cpp | 2 + libsrc/core/python_ngcore.hpp | 17 +---- libsrc/meshing/meshclass.cpp | 125 +++++++++++++++++++++++++++++++- libsrc/meshing/meshtype.cpp | 101 +++++++++++++++++++++++++- libsrc/meshing/meshtype.hpp | 54 ++++++++++++-- libsrc/meshing/parallelmesh.cpp | 2 + libsrc/meshing/python_mesh.cpp | 1 + 10 files changed, 294 insertions(+), 33 deletions(-) diff --git a/libsrc/core/archive.hpp b/libsrc/core/archive.hpp index ad4d5676..af7efc5e 100644 --- a/libsrc/core/archive.hpp +++ b/libsrc/core/archive.hpp @@ -567,6 +567,10 @@ namespace ngcore virtual void FlushBuffer() {} + bool parallel = false; + bool IsParallel() const { return parallel; } + void SetParallel (bool _parallel) { parallel = _parallel; } + private: template friend class RegisterClassForArchive; diff --git a/libsrc/core/array.hpp b/libsrc/core/array.hpp index a1161001..3a775eea 100644 --- a/libsrc/core/array.hpp +++ b/libsrc/core/array.hpp @@ -858,7 +858,7 @@ namespace ngcore size++; } - NETGEN_INLINE Array & operator += (const T & el) + NETGEN_INLINE Array & operator += (const T & el) { Append (el); return *this; diff --git a/libsrc/core/mpi_wrapper.hpp b/libsrc/core/mpi_wrapper.hpp index 8d9631f5..bdf2505b 100644 --- a/libsrc/core/mpi_wrapper.hpp +++ b/libsrc/core/mpi_wrapper.hpp @@ -26,6 +26,9 @@ namespace ngcore template <> struct MPI_typetrait { static MPI_Datatype MPIType () { return MPI_CHAR; } }; + template <> struct MPI_typetrait { + static MPI_Datatype MPIType () { return MPI_CHAR; } }; + template <> struct MPI_typetrait { static MPI_Datatype MPIType () { return MPI_CHAR; } }; @@ -44,6 +47,10 @@ namespace ngcore return MPI_typetrait::MPIType(); } + template + inline MPI_Datatype GetMPIType (T &) { + return GetMPIType(); + } class NgMPI_Comm { @@ -139,8 +146,8 @@ namespace ngcore MPI_Send( const_cast (&s[0]), s.length(), MPI_CHAR, dest, tag, comm); } - template())> - void Send(FlatArray s, int dest, int tag) const { + template())> + void Send(FlatArray s, int dest, int tag) const { MPI_Send (s.Data(), s.Size(), GetMPIType(), dest, tag, comm); } @@ -160,13 +167,13 @@ namespace ngcore } - template ())> - void Recv (FlatArray s, int src, int tag) const { + template ())> + void Recv (FlatArray s, int src, int tag) const { MPI_Recv (s.Data(), s.Size(), GetMPIType (), src, tag, comm, MPI_STATUS_IGNORE); } - template ())> - void Recv (Array & s, int src, int tag) const + template ())> + void Recv (Array & s, int src, int tag) const { MPI_Status status; int len; diff --git a/libsrc/core/python_ngcore.cpp b/libsrc/core/python_ngcore.cpp index 7503a9d1..cf50ace4 100644 --- a/libsrc/core/python_ngcore.cpp +++ b/libsrc/core/python_ngcore.cpp @@ -8,6 +8,8 @@ using std::string; namespace ngcore { bool ngcore_have_numpy = false; + bool parallel_pickling = false; + void SetFlag(Flags &flags, string s, py::object value) { if (py::isinstance(value)) diff --git a/libsrc/core/python_ngcore.hpp b/libsrc/core/python_ngcore.hpp index a089c5e8..44ba8033 100644 --- a/libsrc/core/python_ngcore.hpp +++ b/libsrc/core/python_ngcore.hpp @@ -17,7 +17,8 @@ namespace py = pybind11; namespace ngcore { NGCORE_API extern bool ngcore_have_numpy; - + NGCORE_API extern bool parallel_pickling; + // Python class name type traits template struct PyNameTraits { @@ -297,26 +298,14 @@ namespace ngcore return pybind11::pickle([](T* self) { PyArchive ar; + ar.SetParallel(parallel_pickling); ar & self; - static Timer t("ngspickle 2"); - t.Start(); auto output = pybind11::make_tuple(ar.WriteOut()); - t.Stop(); - /* - GetLogger("Archive")->trace("Pickling output for object of type {} = {}", - Demangle(typeid(T).name()), - std::string(pybind11::str(output))); - */ return output; }, [](const pybind11::tuple & state) { T* val = nullptr; - /* - GetLogger("Archive")->trace("State for unpickling of object of type {} = {}", - Demangle(typeid(T).name()), - std::string(pybind11::str(state[0]))); - */ PyArchive ar(state[0]); ar & val; return val; diff --git a/libsrc/meshing/meshclass.cpp b/libsrc/meshing/meshclass.cpp index 5229f5d2..dc2097b8 100644 --- a/libsrc/meshing/meshclass.cpp +++ b/libsrc/meshing/meshclass.cpp @@ -1281,13 +1281,132 @@ namespace netgen void Mesh :: DoArchive (Archive & archive) { static Timer t("Mesh::Archive"); RegionTimer r(t); - static Timer tvol("Mesh::Archive vol elements"); + +#ifdef PARALLEL + auto comm = GetCommunicator(); + if (archive.IsParallel() && comm.Size() > 1) + { // parallel pickling supported only for output archives + if (comm.Rank() == 0) + archive & dimension; + + // merge points + auto & partop = GetParallelTopology(); + Array globnum(points.Size()); + int maxglob = 0; + for (auto pi : Range(points)) + { + globnum[pi] = partop.GetGlobalPNum(pi); + maxglob = max(globnum[pi], maxglob); + } + + maxglob = comm.AllReduce (maxglob, MPI_MAX); + int numglob = maxglob+1-PointIndex::BASE; + if (comm.Rank() > 0) + { + comm.Send (globnum, 0, 200); + comm.Send (points, 0, 200); + } + else + { + Array globnumi; + Array pointsi; + Array globpoints(numglob); + for (int j = 1; j < comm.Size(); j++) + { + comm.Recv (globnumi, j, 200); + comm.Recv (pointsi, j, 200); + for (auto i : Range(globnumi)) + globpoints[globnumi[i]] = pointsi[i]; + } + archive & globpoints; + } + + + // sending surface elements + auto copy_el2d (surfelements); + for (auto & el : copy_el2d) + for (auto & pi : el.PNums()) + pi = globnum[pi]; + + if (comm.Rank() > 0) + comm.Send(copy_el2d, 0, 200); + else + { + Array el2di; + for (int j = 1; j < comm.Size(); j++) + { + comm.Recv(el2di, j, 200); + for (auto & el : el2di) + copy_el2d += el; + } + archive & copy_el2d; + } + + + // sending volume elements + auto copy_el3d (volelements); + for (auto & el : copy_el3d) + for (auto & pi : el.PNums()) + pi = globnum[pi]; + + if (comm.Rank() > 0) + comm.Send(copy_el3d, 0, 200); + else + { + Array el3di; + for (int j = 1; j < comm.Size(); j++) + { + comm.Recv(el3di, j, 200); + for (auto & el : el3di) + copy_el3d += el; + } + archive & copy_el3d; + } + + + // sending 1D elements + auto copy_el1d (segments); + for (auto & el : copy_el1d) + for (auto & pi : el.pnums) + if (pi != PointIndex(PointIndex::INVALID)) + pi = globnum[pi]; + + if (comm.Rank() > 0) + comm.Send(copy_el1d, 0, 200); + else + { + Array el1di; + for (int j = 1; j < comm.Size(); j++) + { + comm.Recv(el1di, j, 200); + for (auto & el : el1di) + copy_el1d += el; + } + archive & copy_el1d; + } + + if (comm.Rank() == 0) + { + archive & facedecoding; + archive & materials & bcnames & cd2names & cd3names; + auto mynv = numglob; + archive & mynv; // numvertices; + archive & *ident; + + archive.Shallow(geometry); + archive & *curvedelems; + } + + if (comm.Rank() == 0) + return; + } +#endif + + archive & dimension; archive & points; archive & surfelements; - tvol.Start(); archive & volelements; - tvol.Stop(); archive & segments; archive & facedecoding; archive & materials & bcnames & cd2names & cd3names; diff --git a/libsrc/meshing/meshtype.cpp b/libsrc/meshing/meshtype.cpp index 0730c9d8..9bebaec4 100644 --- a/libsrc/meshing/meshtype.cpp +++ b/libsrc/meshing/meshtype.cpp @@ -45,6 +45,102 @@ namespace netgen } return type; } + + + MPI_Datatype Element2d :: MyGetMPIType ( ) + { + static MPI_Datatype type = MPI_DATATYPE_NULL; + static MPI_Datatype htype = MPI_DATATYPE_NULL; + if (type == MPI_DATATYPE_NULL) + { + Element2d hel; + int blocklen[] = { ELEMENT2D_MAXPOINTS, 1, 1, 1 }; + MPI_Aint displ[] = + { (char*)&hel.pnum[0] - (char*)&hel, + (char*)&hel.index - (char*)&hel, + (char*)&hel.typ - (char*)&hel, + (char*)&hel.np - (char*)&hel + }; + MPI_Datatype types[] = { GetMPIType(), GetMPIType(hel.index), + GetMPIType(hel.typ), GetMPIType(hel.np) }; + // *testout << "displ = " << displ[0] << ", " << displ[1] << ", " << displ[2] << endl; + // *testout << "sizeof = " << sizeof (MeshPoint) << endl; + MPI_Type_create_struct (4, blocklen, displ, types, &htype); + MPI_Type_commit ( &htype ); + MPI_Aint lb, ext; + MPI_Type_get_extent (htype, &lb, &ext); + // *testout << "lb = " << lb << endl; + // *testout << "ext = " << ext << endl; + ext = sizeof (Element2d); + MPI_Type_create_resized (htype, lb, ext, &type); + MPI_Type_commit ( &type ); + } + return type; + } + + MPI_Datatype Element :: MyGetMPIType ( ) + { + static MPI_Datatype type = MPI_DATATYPE_NULL; + static MPI_Datatype htype = MPI_DATATYPE_NULL; + if (type == MPI_DATATYPE_NULL) + { + Element hel; + int blocklen[] = { ELEMENT_MAXPOINTS, 1, 1, 1 }; + MPI_Aint displ[] = + { (char*)&hel.pnum[0] - (char*)&hel, + (char*)&hel.index - (char*)&hel, + (char*)&hel.typ - (char*)&hel, + (char*)&hel.np - (char*)&hel + }; + MPI_Datatype types[] = { GetMPIType(), GetMPIType(hel.index), + GetMPIType(hel.typ), GetMPIType(hel.np) }; + // *testout << "displ = " << displ[0] << ", " << displ[1] << ", " << displ[2] << endl; + // *testout << "sizeof = " << sizeof (MeshPoint) << endl; + MPI_Type_create_struct (4, blocklen, displ, types, &htype); + MPI_Type_commit ( &htype ); + MPI_Aint lb, ext; + MPI_Type_get_extent (htype, &lb, &ext); + // *testout << "lb = " << lb << endl; + // *testout << "ext = " << ext << endl; + ext = sizeof (Element); + MPI_Type_create_resized (htype, lb, ext, &type); + MPI_Type_commit ( &type ); + } + return type; + } + + MPI_Datatype Segment :: MyGetMPIType ( ) + { + static MPI_Datatype type = MPI_DATATYPE_NULL; + static MPI_Datatype htype = MPI_DATATYPE_NULL; + if (type == MPI_DATATYPE_NULL) + { + Segment hel; + int blocklen[] = { 3, 1, 1, 1 }; + MPI_Aint displ[] = + { (char*)&hel.pnums[0] - (char*)&hel, + (char*)&hel.edgenr - (char*)&hel, + (char*)&hel.cd2i - (char*)&hel, + (char*)&hel.si - (char*)&hel + }; + MPI_Datatype types[] = { + GetMPIType(), GetMPIType(hel.edgenr), GetMPIType(hel.cd2i), GetMPIType(hel.si) + }; + // *testout << "displ = " << displ[0] << ", " << displ[1] << ", " << displ[2] << endl; + // *testout << "sizeof = " << sizeof (MeshPoint) << endl; + MPI_Type_create_struct (4, blocklen, displ, types, &htype); + MPI_Type_commit ( &htype ); + MPI_Aint lb, ext; + MPI_Type_get_extent (htype, &lb, &ext); + // *testout << "lb = " << lb << endl; + // *testout << "ext = " << ext << endl; + ext = sizeof (Segment); + MPI_Type_create_resized (htype, lb, ext, &type); + MPI_Type_commit ( &type ); + } + return type; + } + #endif @@ -158,7 +254,8 @@ namespace netgen << " si = " << seg.si << ", edgenr = " << seg.edgenr; return s; } - /* + + // needed, e.g. for MPI communication Element2d :: Element2d () { for (int i = 0; i < ELEMENT2D_MAXPOINTS; i++) @@ -177,7 +274,7 @@ namespace netgen strongrefflag = false; is_curved = false; } - */ + Element2d :: Element2d (int anp) { for (int i = 0; i < ELEMENT2D_MAXPOINTS; i++) diff --git a/libsrc/meshing/meshtype.hpp b/libsrc/meshing/meshtype.hpp index d572f9d5..e38f7ad8 100644 --- a/libsrc/meshing/meshtype.hpp +++ b/libsrc/meshing/meshtype.hpp @@ -228,8 +228,8 @@ namespace netgen { int i; public: - ElementIndex () { ; } - ElementIndex (int ai) : i(ai) { ; } + ElementIndex () = default; + constexpr ElementIndex (int ai) : i(ai) { ; } ElementIndex & operator= (const ElementIndex & ai) { i = ai.i; return *this; } ElementIndex & operator= (int ai) { i = ai; return *this; } operator int () const { return i; } @@ -288,8 +288,8 @@ namespace netgen { int i; public: - SegmentIndex () { ; } - SegmentIndex (int ai) : i(ai) { ; } + SegmentIndex () = default; + constexpr SegmentIndex (int ai) : i(ai) { ; } SegmentIndex & operator= (const SegmentIndex & ai) { i = ai.i; return *this; } SegmentIndex & operator= (int ai) { i = ai; return *this; } @@ -393,7 +393,7 @@ namespace netgen /// ELEMENT_TYPE typ; /// number of points - unsigned int np:4; + int8_t np; bool badel:1; bool refflag:1; // marked for refinement bool strongrefflag:1; @@ -417,7 +417,7 @@ namespace netgen public: /// - Element2d () = default; + Element2d (); Element2d (const Element2d &) = default; Element2d (Element2d &&) = default; Element2d & operator= (const Element2d &) = default; @@ -548,6 +548,11 @@ namespace netgen ar & pnum[i]; } +#ifdef PARALLEL + static MPI_Datatype MyGetMPIType(); +#endif + + void SetIndex (int si) { index = si; } /// int GetIndex () const { return index; } @@ -699,7 +704,7 @@ namespace netgen /// ELEMENT_TYPE typ; /// number of points (4..tet, 5..pyramid, 6..prism, 8..hex, 10..quad tet, 12..quad prism) - int np:6; + int8_t np; /// class flagstruct { public: @@ -826,6 +831,10 @@ namespace netgen for (size_t i = 0; i < np; i++) ar & pnum[i]; } + +#ifdef PARALLEL + static MPI_Datatype MyGetMPIType(); +#endif /// void SetIndex (int si) { index = si; } @@ -1074,6 +1083,10 @@ namespace netgen */ void DoArchive (Archive & ar); +#ifdef PARALLEL + static MPI_Datatype MyGetMPIType(); +#endif + }; ostream & operator<<(ostream & s, const Segment & seg); @@ -1547,6 +1560,33 @@ namespace netgen } +#ifdef PARALLEL +namespace ngcore +{ + template <> struct MPI_typetrait { + static MPI_Datatype MPIType () { return MPI_INT; } + }; + + template <> struct MPI_typetrait { + static MPI_Datatype MPIType () { return MPI_CHAR; } + }; + + template <> struct MPI_typetrait { + static MPI_Datatype MPIType () { return netgen::MeshPoint::MyGetMPIType(); } + }; + + template <> struct MPI_typetrait { + static MPI_Datatype MPIType () { return netgen::Element::MyGetMPIType(); } + }; + template <> struct MPI_typetrait { + static MPI_Datatype MPIType () { return netgen::Element2d::MyGetMPIType(); } + }; + template <> struct MPI_typetrait { + static MPI_Datatype MPIType () { return netgen::Segment::MyGetMPIType(); } + }; + +} +#endif #endif diff --git a/libsrc/meshing/parallelmesh.cpp b/libsrc/meshing/parallelmesh.cpp index 9af0d7a6..a7c13d23 100644 --- a/libsrc/meshing/parallelmesh.cpp +++ b/libsrc/meshing/parallelmesh.cpp @@ -25,10 +25,12 @@ namespace metis { using namespace metis; #endif +/* namespace ngcore { template <> struct MPI_typetrait { static MPI_Datatype MPIType () { return MPI_INT; } }; } +*/ namespace netgen { diff --git a/libsrc/meshing/python_mesh.cpp b/libsrc/meshing/python_mesh.cpp index 0d0877b0..3641ca15 100644 --- a/libsrc/meshing/python_mesh.cpp +++ b/libsrc/meshing/python_mesh.cpp @@ -1251,6 +1251,7 @@ grow_edges : bool = False py::class_ (m, "ClearSolutionClass") .def(py::init<>()) ; + m.def("SetParallelPickling", [](bool par) { parallel_pickling = par; }); } PYBIND11_MODULE(libmesh, m) { From 12b2e073ac005be52015f1ebd9659b1d0148a002 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Wed, 19 Aug 2020 16:46:32 +0200 Subject: [PATCH 114/384] CSG for 2D --- libsrc/geom2d/CMakeLists.txt | 4 +- libsrc/geom2d/csg2d.cpp | 1549 +++++++++++++++++++++++++++++++ libsrc/geom2d/csg2d.hpp | 583 ++++++++++++ libsrc/geom2d/geometry2d.hpp | 1 + libsrc/geom2d/python_geom2d.cpp | 32 + libsrc/gprim/geom2d.cpp | 235 ----- libsrc/gprim/geom2d.hpp | 34 - libsrc/gprim/spline.hpp | 4 + python/geom2d.py | 2 +- 9 files changed, 2172 insertions(+), 272 deletions(-) create mode 100644 libsrc/geom2d/csg2d.cpp create mode 100644 libsrc/geom2d/csg2d.hpp diff --git a/libsrc/geom2d/CMakeLists.txt b/libsrc/geom2d/CMakeLists.txt index f496448d..466cc5c4 100644 --- a/libsrc/geom2d/CMakeLists.txt +++ b/libsrc/geom2d/CMakeLists.txt @@ -1,5 +1,5 @@ add_definitions(-DNGLIB_EXPORTS) -add_library(geom2d ${NG_LIB_TYPE} genmesh2d.cpp geometry2d.cpp python_geom2d.cpp ) +add_library(geom2d ${NG_LIB_TYPE} csg2d.cpp genmesh2d.cpp geometry2d.cpp python_geom2d.cpp ) if(APPLE) set_target_properties( geom2d PROPERTIES SUFFIX ".so") endif(APPLE) @@ -20,6 +20,6 @@ endif(USE_GUI) install(FILES geometry2d.hpp spline2d.hpp - vsgeom2d.hpp + vsgeom2d.hpp csg2d.hpp DESTINATION ${NG_INSTALL_DIR_INCLUDE}/geom2d COMPONENT netgen_devel ) diff --git a/libsrc/geom2d/csg2d.cpp b/libsrc/geom2d/csg2d.cpp new file mode 100644 index 00000000..96bf07c5 --- /dev/null +++ b/libsrc/geom2d/csg2d.cpp @@ -0,0 +1,1549 @@ +#include +#include +#include +#include +#include + +#include "csg2d.hpp" + +// Polygon clipping algorithm based on: +// Foster, Erich & Hormann, Kai & Popa, Romeo. (2019). Clipping Simple Polygons with Degenerate Intersections. Computers & Graphics: X. 2. 100007. 10.1016/j.cagx.2019.100007. +// extended to handle quadratic spline segments + +namespace netgen +{ + +constexpr static double EPSILON=0.000000001; + +void ToggleLabel(EntryExitLabel& status) +{ + if (status == ENTRY) + { + status = EXIT; + return; + } + if (status == EXIT) + { + status = ENTRY; + return; + } +} + +Spline Split( const Spline & s, double t0, double t1 ) +{ + if(t0==0.0 && t1==1.0) return s; + + Point<2> a = s.StartPI(); + if(t0!=0.0) + a = s.GetPoint(t0); + + Point<2> c = s.EndPI(); + if(t1!=1.0) + c = s.GetPoint(t1); + + // Find new midpoints by cutting the tangents at the new end points + auto tang0 = s.GetTangent(t0); + auto tang1 = s.GetTangent(t1); + + netgen::Mat<2,2> m, minv; + m(0,0) = tang0[0]; + m(1,0) = tang0[1]; + m(0,1) = -tang1[0]; + m(1,1) = -tang1[1]; + + CalcInverse(m, minv); + + Vec<2> lam = minv*(c-a); + + Point<2> b = a+lam[0]*tang0; + + auto res = Spline{a, b, c}; + + // compute weight of new spline such that p lies on it + Point<2> p = s.GetPoint(0.5*(t0+t1)); + double A = (p[1]-a[1])*(b[0]-p[0]) - (p[0]-a[0])*(b[1]-p[1]); + double B = (p[1]-c[1])*(b[0]-p[0]) - (p[0]-c[0])*(b[1]-p[1]); + double det = sqrt(-A*B); + double tt = (B-det)/(A+det); + auto v = b-p; + int dim = fabs(v[0]) > fabs(v[1]) ? 0 : 1; + double weight = fabs(tt*(p[dim]-a[dim])/v[dim] + 1.0/tt*(p[dim]-c[dim])/v[dim]); + res.SetWeight(weight); + return res; +} + +Vertex * Vertex :: Insert(Point<2> p, double lam) +{ + auto vnew = make_unique(p); + vnew->lam = lam; + + Vertex * current = this; + + if(lam > -1.0) + { + do { + current = current->next; + } while (!current->is_source && current->lam < lam); + } + else + current = current->next; + + auto pre = current->prev; + vnew->bc = pre->bc; + + pre->next = vnew.get(); + vnew->prev = pre; + vnew->next = current; + + vnew->pnext = std::move(current->prev->pnext); + + current->prev = vnew.get(); + + pre->pnext = std::move(vnew); + + return pre->next; +} + +IntersectionType ClassifyNonOverlappingIntersection( double alpha, double beta ) +{ + // classify alpha + bool alpha_is_0 = false; + bool alpha_in_0_1 = false; + + if ( (alpha > EPSILON) && (alpha < 1.0-EPSILON) ) + alpha_in_0_1 = true; + else + if (fabs(alpha) <= EPSILON) + alpha_is_0 = true; + + // classify beta + bool beta_is_0 = false; + bool beta_in_0_1 = false; + + if ( (beta > EPSILON) && (beta < 1.0-EPSILON) ) + beta_in_0_1 = true; + else + if (fabs(beta) <= EPSILON) + beta_is_0 = true; + + // distinguish intersection types + if (alpha_in_0_1 && beta_in_0_1) + return (X_INTERSECTION); + + if (alpha_is_0 && beta_in_0_1) + return (T_INTERSECTION_Q); + + if (beta_is_0 && alpha_in_0_1) + return (T_INTERSECTION_P); + + if (alpha_is_0 && beta_is_0) + return (V_INTERSECTION); + + return NO_INTERSECTION; +} + +IntersectionType ClassifyOverlappingIntersection( double alpha, double beta ) +{ + // classify alpha + bool alpha_is_0 = false; + bool alpha_in_0_1 = false; + bool alpha_not_in_0_1 = false; + + if ( (alpha > EPSILON) && (alpha < 1.0-EPSILON) ) + alpha_in_0_1 = true; + else + if (fabs(alpha) <= EPSILON) + alpha_is_0 = true; + else + alpha_not_in_0_1 = true; + + // classify beta + bool beta_is_0 = false; + bool beta_in_0_1 = false; + bool beta_not_in_0_1 = false; + + if ( (beta > EPSILON) && (beta < 1.0-EPSILON) ) + beta_in_0_1 = true; + else + if (fabs(alpha) <= EPSILON) + beta_is_0 = true; + else + beta_not_in_0_1 = true; + + // distinguish intersection types + if (alpha_in_0_1 && beta_in_0_1) + return (X_OVERLAP); + + if (alpha_not_in_0_1 && beta_in_0_1) + return (T_OVERLAP_Q); + + if (beta_not_in_0_1 && alpha_in_0_1) + return (T_OVERLAP_P); + + if (alpha_is_0 && beta_is_0) + return (V_OVERLAP); + + return NO_INTERSECTION; +} + +IntersectionType intersect(const Point<2> P1, const Point<2> P2, const Point<2> Q1, const Point<2> Q2, double& alpha, double& beta) +{ + double AP1 = Area(P1,Q1,Q2); + double AP2 = Area(P2,Q1,Q2); + + if (fabs(AP1-AP2) > EPSILON) + { + // (P1,P2) and (Q1,Q2) are not parallel + + double AQ1 = Area(Q1,P1,P2); + double AQ2 = Area(Q2,P1,P2); + + alpha = AP1 / (AP1-AP2); + beta = AQ1 / (AQ1-AQ2); + + return ClassifyNonOverlappingIntersection(alpha, beta); + } + else + if (fabs(AP1) < EPSILON) + { + // (P1,P2) and (Q1,Q2) are collinear + + auto dP = P2-P1; + auto dQ = Q2-Q1; + auto PQ = Q1-P1; + + alpha = (PQ*dP) / (dP*dP); + beta = -(PQ*dQ) / (dQ*dQ); + + return ClassifyOverlappingIntersection(alpha, beta); + } + return NO_INTERSECTION; +} + +IntersectionType IntersectSplineSegment( const Spline & s, const Point<2> & r0, const Point<2> & r1, double& alpha, double& beta ) +{ + Point<2> p0 = s.StartPI(); + Point<2> p1 = s.TangentPoint(); + Point<2> p2 = s.EndPI(); + + auto vr = r1-r0; + double a0 = vr[1]*(p0[0] - r0[0]) - vr[0]*(p0[1] - r0[1]); + double a1 = vr[1]*(p1[0] - r0[0]) - vr[0]*(p1[1] - r0[1]); + double a2 = vr[1]*(p2[0] - r0[0]) - vr[0]*(p2[1] - r0[1]); + a1 *= s.GetWeight(); + + double a_ = a0-a1+a2; + double b_ = a1-2*a0; + double c_ = a0; + + double det = b_*b_ - 4*a_*c_; + if(det<0.0) + return NO_INTERSECTION; + double sqrt_det = sqrt(det); + double t1 = 1.0/(2*a_) * (-b_ + sqrt_det); + double t2 = 1.0/(2*a_) * (-b_ - sqrt_det); + + double t = min(t1,t2); + if(t fabs(vr[1]) ? 0 : 1; + beta = 1.0/vr[dim] * (s.GetPoint(t)[dim] - r0[dim]); + + return ClassifyNonOverlappingIntersection(alpha, beta); +} + +IntersectionType IntersectSplineSegment1( const Spline & s, const Point<2> & r0, const Point<2> & r1, double& alpha, double& beta ) +{ + Point<2> p0 = s.StartPI(); + Point<2> p1 = s.TangentPoint(); + Point<2> p2 = s.EndPI(); + + auto vr = r1-r0; + double a0 = vr[1]*(p0[0] - r0[0]) - vr[0]*(p0[1] - r0[1]); + double a1 = vr[1]*(p1[0] - r0[0]) - vr[0]*(p1[1] - r0[1]); + double a2 = vr[1]*(p2[0] - r0[0]) - vr[0]*(p2[1] - r0[1]); + a1 *= s.GetWeight(); + + double a_ = a0-a1+a2; + double b_ = a1-2*a0; + double c_ = a0; + + double det = b_*b_ - 4*a_*c_; + if(det<0.0) + return NO_INTERSECTION; + double sqrt_det = sqrt(det); + double vbeta[2]; + vbeta[0] = 1.0/(2*a_) * (-b_ + sqrt_det); + vbeta[1] = 1.0/(2*a_) * (-b_ - sqrt_det); + + int dim = fabs(vr[0]) > fabs(vr[1]) ? 0 : 1; + double valpha[2]; + valpha[0] = 1.0/vr[dim] * (s.GetPoint(vbeta[0])[dim] - r0[dim]); + valpha[1] = 1.0/vr[dim] * (s.GetPoint(vbeta[1])[dim] - r0[dim]); + + + IntersectionType vtype[2]; + vtype[0] = ClassifyNonOverlappingIntersection(valpha[0], vbeta[0]); + vtype[1] = ClassifyNonOverlappingIntersection(valpha[1], vbeta[1]); + + if(valpha[0]>valpha[1]) + { + swap(valpha[0], valpha[1]); + swap(vbeta[0], vbeta[1]); + swap(vtype[0], vtype[1]); + } + + int choice = 0; + if(vtype[0]==NO_INTERSECTION && vtype[1]!=NO_INTERSECTION) + choice = 1; + + if(valpha[0] < alpha+EPSILON) + choice = 1; + + if(valpha[choice] < alpha+EPSILON) + return NO_INTERSECTION; + + alpha = valpha[choice]; + beta = vbeta[choice]; + return vtype[choice]; +} + +bool IsOverlapping( Spline p, Spline s, double & alpha, double & beta, IntersectionType & type ) +{ + + auto p_mid = Center(p.StartPI(), p.EndPI()); + auto s_mid = Center(s.StartPI(), s.EndPI()); + + double lam0 = -1e3*EPSILON; + double lam1 = -1e3*EPSILON; + alpha=-1e8; + beta=-1e8; + + // Check if s.p0 lies on p and vice versa, also check if tangents are in same direction (TODO: TEST) + // If so, assume overlapping splines + // TODO: Better checks! False positives could happen here! + IntersectSplineSegment1( p, s.StartPI(), p_mid, lam0, alpha ); + IntersectSplineSegment1( s, p.StartPI(), s_mid, lam1, beta ); + auto tang0 = s.GetTangent(0.); + auto tang1 = p.GetTangent(alpha); + double err = tang0*tang1; + err*=err; + err *= 1.0/(tang0.Length2()*tang1.Length2()); + + if(fabs(lam0) < 1e3*EPSILON && fabs(lam1) < 1e3*EPSILON /*&& err < EPSILON*/) + { + type = ClassifyOverlappingIntersection( alpha, beta ); + return true; + } + return false; +} + +bool IsInsideTrig( const array,3> & t, Point<2> r ) +{ + int w = 0; + Point<2> trig[4] = {t[0],t[1],t[2],t[0]}; + for(auto i : Range(3)) + w += CalcSide(trig[i], trig[i+1], r); + return ( (w % 2) != 0 ); +} + + +IntersectionType IntersectTrig( Point<2> p0, Point<2> p1, const array,3> & trig) +{ + Point<2> lt[4] = { trig[0], trig[1], trig[2], trig[0] }; + + double alpha, beta; + for(auto i : IntRange(3)) + { + auto type = intersect(p0, p1, lt[i], lt[i+1], alpha, beta); + if(type != NO_INTERSECTION) + return type; + } + + return NO_INTERSECTION; +} + +bool IntersectTrigs( const array,3> & trig0, const array,3> & trig1) +{ + Point<2> lt0[4] = { trig0[0], trig0[1], trig0[2], trig0[0] }; + + for(auto i : IntRange(3)) + { + if(IntersectTrig(lt0[i], lt0[i+1], trig1)) + return true; + if(IsInsideTrig(trig0, trig1[i])) + return true; + if(IsInsideTrig(trig1, trig0[i])) + return true; + } + return false; +} + +bool BisectIntersect( Spline p, Spline s, double &t0, double &t1, double &s0, double &s1, int depth=-50) +{ + if(depth==0) + { + s0 = s1; + t0 = t1; + return true; + } + + bool side = depth%2==0; + + double & lam0 = side ? t0 : s0; + double & lam1 = side ? t1 : s1; + Spline & spline = side ? p : s; + Spline & spline_other = side ? s : p; + + double lam_mid = 0.5*(lam0+lam1); + auto left = Split(spline, lam0, lam_mid); + auto right = Split(spline, lam_mid, lam1); + + double & lam0_other = side ? s0 : t0; + double & lam1_other = side ? s1 : t1; + auto curr = Split(spline_other, lam0_other, lam1_other); + + bool left_hull_intersecting = IntersectTrigs( {left.StartPI(), left.TangentPoint(), left.EndPI()}, {curr.StartPI(), curr.TangentPoint(), curr.EndPI()}); + bool right_hull_intersecting = IntersectTrigs( {right.StartPI(), right.TangentPoint(), right.EndPI()}, {curr.StartPI(), curr.TangentPoint(), curr.EndPI()}); + + // TODO: Additionaly check if one spline intersects with convex hull of other? + // // Check if one spline intersects with convex hull of spline + // if(left_hull_intersecting) + // { + // double a,b; + // left_hull_intersecting = left.Intersect( curr.p0, curr.p1, a, b ); + // left_hull_intersecting |= left.Intersect( curr.p1, curr.p2, a, b ); + // left_hull_intersecting |= left.Intersect( curr.p2, curr.p0, a, b ); + // } + // + // if(right_hull_intersecting) + // { + // double a,b; + // right_hull_intersecting = right.Intersect( curr.p0, curr.p1, a, b ); + // right_hull_intersecting |= right.Intersect( curr.p1, curr.p2, a, b ); + // right_hull_intersecting |= right.Intersect( curr.p2, curr.p0, a, b ); + // } + + + if(!left_hull_intersecting && !right_hull_intersecting) + return false; + + if(left_hull_intersecting && right_hull_intersecting) + { + // cout << "intersect both sides " << endl; + double temp_lam; + temp_lam = lam1; + lam1 = lam_mid; + + double t0_ = t0; + double t1_ = t1; + double s0_ = s0; + double s1_ = s1; + + // cout << "recursive bisect " << t0 << ',' << t1 << ',' << s0 << ',' << s1 << endl; + bool first_intersecting = BisectIntersect(p, s, t0_, t1_, s0_, s1_, depth+1); + if(first_intersecting) + { + t0 = t0_; + t1 = t1_; + s0 = s0_; + s1 = s1_; + return true; + } + else + { + // cout << "search other side " << endl; + // no first intersection -> search other side + lam1 = temp_lam; + left_hull_intersecting = false; + } + } + + if(left_hull_intersecting) + lam1 = lam_mid; + else + lam0 = lam_mid; + + return BisectIntersect(p, s, t0, t1, s0, s1, depth+1); +} + +bool NewtonIntersect( Spline p, Spline s, double & alpha, double & beta ) +{ + + Point<2> p0, s0; + Vec<2> dp, ds, ddp, dds; + + p.GetDerivatives(alpha, p0, dp, ddp); + s.GetDerivatives(beta, s0, ds, dds); + + netgen::Mat<2,2> m, minv; + + m(0,0) = dp[0]; + m(1,0) = dp[1]; + m(0,1) = -ds[0]; + m(1,1) = -ds[1]; + + CalcInverse(m, minv); + + Vec<2> res = s0-p0; + Vec<2> h = minv*res; + alpha +=h[0]; + beta +=h[1]; + return true; +} + + +IntersectionType Intersect( Spline p, Spline s, double &alpha, double &beta) +{ + bool is_convex_hull_intersecting = IntersectTrigs( {p.StartPI(), p.TangentPoint(), p.EndPI()}, {s.StartPI(), s.TangentPoint(), s.EndPI()}); + if(!is_convex_hull_intersecting) + return NO_INTERSECTION; + + { + // Check if splines overlap + double alpha_ = alpha; + double beta_ = beta; + IntersectionType overlap_type; + bool have_overlap = IsOverlapping( p, s, alpha_, beta_, overlap_type ); + if(have_overlap) + { + alpha = alpha_; + beta = beta_; + return overlap_type; + } + } + + // Bisection + double t1 = 1.0; + double s1 = 1.0; + + bool have_intersection = false; + if(alpha>0.0) // alpha > 0 means, we have found one intersection already + { + // reverse parametrization of first spline to make sure, we find the second intersection first + auto p_ = Spline{p.EndPI(), p.TangentPoint(), p.StartPI(), p.GetWeight()}; + t1 = 1.0-alpha; + alpha = 0.0; + beta = 0.0; + + have_intersection = BisectIntersect(p_,s,alpha,t1,beta,s1); + alpha = 1.0-alpha; + } + else + have_intersection = BisectIntersect(p,s,alpha,t1,beta,s1); + + if(have_intersection) + { + for(auto i : IntRange(10)) + NewtonIntersect(p, s, alpha, beta); + return ClassifyNonOverlappingIntersection( alpha, beta ); + } + + return NO_INTERSECTION; +} + + +IntersectionType intersect(const Edge& edgeP, const Edge& edgeQ, double& alpha, double& beta) +{ + const Point<2>& P1 = *edgeP.v0; + const Point<2>& P2 = *edgeP.v1; + const Point<2>& Q1 = *edgeQ.v0; + const Point<2>& Q2 = *edgeQ.v1; + + if(edgeP.v0->spline) + { + if(edgeQ.v0->spline) + return Intersect(*edgeP.v0->spline, *edgeQ.v0->spline, alpha, beta); + else + return IntersectSplineSegment(*edgeP.v0->spline, Q1, Q2, alpha, beta); + } + else + { + if(edgeQ.v0->spline) + return IntersectSplineSegment1(*edgeQ.v0->spline, P1, P2, alpha, beta); + else + return intersect(P1, P2, Q1, Q2, alpha, beta); + } +} + +void AddIntersectionPoint(Edge edgeP, Edge edgeQ, IntersectionType i, double alpha, double beta) +{ + Point<2> I; + Vertex* I_P; + Vertex* I_Q; + + Vertex* P1 = edgeP.v0; + Vertex* Q1 = edgeQ.v0; + + switch(i) + { + case X_INTERSECTION: + if(edgeP.v0->spline) + I = edgeP.v0->spline->GetPoint(alpha); + else + I = *edgeP.v0 + alpha*(*edgeP.v1 - *edgeP.v0); + I_P = edgeP.v0->Insert(I, alpha); + I_Q = edgeQ.v0->Insert(I, beta); + I_P->Link(I_Q); + break; + + case X_OVERLAP: + I_Q = edgeQ.v0->Insert(*P1, beta); + P1->Link( I_Q); + + I_P = edgeP.v0->Insert(*Q1, alpha); + I_P->Link( Q1); + break; + + case T_INTERSECTION_Q: + case T_OVERLAP_Q: + I_Q = edgeQ.v0->Insert(*P1, beta); + P1->Link( I_Q); + break; + + case T_INTERSECTION_P: + case T_OVERLAP_P: + I_P = edgeP.v0->Insert(*Q1, alpha); + I_P->Link( Q1); + break; + + case V_INTERSECTION: + case V_OVERLAP: + P1->Link(Q1); + break; + default: + break; + } +} + + +void ComputeIntersections(Solid2d & sp, Solid2d & sq) +{ + auto & PP = sp.polys; + auto & QQ = sq.polys; + + for (Polygon2d& P : PP) + for (Edge edgeP : P.Edges(SOURCE)) + for (Polygon2d& Q : QQ) + for (Edge edgeQ : Q.Edges(SOURCE)) + { + double alpha = 0.0; + double beta = 0.0; + IntersectionType i = intersect(edgeP, edgeQ, alpha, beta); + AddIntersectionPoint(edgeP, edgeQ, i, alpha, beta); + if(i==X_INTERSECTION && (edgeP.v0->spline || edgeQ.v0->spline)) + { + double alpha1 = alpha+1e2*EPSILON; + double beta1 = 0.0; //beta+1e2*EPSILON; + + // search for possible second intersection + i = intersect(edgeP, edgeQ, alpha1, beta1); + // cout << "second intersection " << i << ',' << alpha1 << ',' << beta1 << ',' << alpha1-alpha << ',' << beta1-beta << endl; + if(i!=NO_INTERSECTION && alpha+EPSILON MP; + if(edgeP.v0->spline) + { + MP = edgeP.v0->spline->GetPoint(alpha_mid); + edgeP.v0->Insert(MP, alpha_mid); + } + else + MP = edgeQ.v0->spline->GetPoint(beta_mid); + + if(edgeQ.v0->spline) + edgeQ.v0->Insert(MP, beta_mid); + + AddIntersectionPoint(edgeP, edgeQ, i, alpha1, beta1); + } + } + } + + // Split splines at new vertices + auto split_spline_at_vertex = [](Vertex *v) + { + if(!v->spline) + return; + Spline ori{*v->spline}; + Vertex * curr = v; + do + { + auto next = curr->next; + if(!curr->is_source || !next->is_source) + { + double t0 = curr->is_source ? 0.0 : curr->lam; + double t1 = next->is_source ? 1.0 : next->lam; + curr->spline = Split(ori, t0, t1); + } + curr = next; + } while(!curr->is_source); + }; + + for (Polygon2d& P : PP) + for (Vertex* v : P.Vertices(SOURCE)) + split_spline_at_vertex(v); + for (Polygon2d& Q : QQ) + for (Vertex* v : Q.Vertices(SOURCE)) + split_spline_at_vertex(v); +} + +enum RelativePositionType +{ + LEFT, + RIGHT, + IS_P_m, + IS_P_p +}; + +RelativePositionType oracle(bool prev, Vertex* P1, Vertex* P2, Vertex* P3) +{ + Vertex* Q; + Point<2> q; + if(prev) + { + Q = P2->neighbour->prev; + q = *Q; + if(Q->spline) + q = Q->spline->TangentPoint(); + } + else + { + Q = P2->neighbour->next; + q = *Q; + if(P2->spline) + q = P2->neighbour->spline->TangentPoint(); + } + + // is Q linked to P1 ? + if ( P1->is_intersection && (P1->neighbour == Q) ) + return(IS_P_m); + + // is Q linked to P2 ? + if ( P3->is_intersection && (P3->neighbour == Q) ) + return(IS_P_p); + + Point<2> p1 = *P1; + Point<2> p2 = *P2; + Point<2> p3 = *P3; + + if(P1->spline) + p1 = P1->spline->TangentPoint(); + if(P2->spline) + p3 = P2->spline->TangentPoint(); + + // check relative position of Q with respect to chain (P1,P2,P3) + double s1 = Area( q, p1, p2); + double s2 = Area( q, p2, p3); + double s3 = Area( p1, p2, p3); + + if (s3 > 0) + { + // chain makes a left turn + if (s1 > 0 && s2 > 0) + return(LEFT); + else + return(RIGHT); + } + else + { + // chain makes a right turn (or is straight) + if (s1 < 0 && s2 < 0) + return(RIGHT); + else + return(LEFT); + } +} + +void LabelIntersections(Solid2d & sp, Solid2d & sq, Solid2d & sr, bool UNION) +{ + auto & PP = sp.polys; + auto & QQ = sq.polys; + auto & RR = sr.polys; + + // 1) initial classification + for (Polygon2d& P : PP) + for (Vertex* I : P.Vertices(INTERSECTION)) + { + + // determine local configuration at this intersection vertex + Vertex* P_m = I->prev; + Vertex* P_p = I->next; + + // check positions of Q- and Q+ relative to (P-, I, P+) + RelativePositionType Q_m_type = oracle(true, P_m, I, P_p); + RelativePositionType Q_p_type = oracle(false, P_m, I, P_p); + + // check non-overlapping cases + if ((Q_m_type == LEFT && Q_p_type == RIGHT) || + (Q_m_type == RIGHT && Q_p_type == LEFT )) + { + I->label = CROSSING; + } + + if ((Q_m_type == LEFT && Q_p_type == LEFT ) || + (Q_m_type == RIGHT && Q_p_type == RIGHT)) + { + I->label = BOUNCING; + } + + // check overlapping cases + if ( ( (Q_p_type == IS_P_p) && (Q_m_type == RIGHT) ) || + ( (Q_m_type == IS_P_p) && (Q_p_type == RIGHT) ) ) + I->label = LEFT_ON; + + if ( ( (Q_p_type == IS_P_p) && (Q_m_type == LEFT) ) || + ( (Q_m_type == IS_P_p) && (Q_p_type == LEFT) ) ) + I->label = RIGHT_ON; + + if ( ( (Q_p_type == IS_P_p) && (Q_m_type == IS_P_m) ) || + ( (Q_m_type == IS_P_p) && (Q_p_type == IS_P_m) ) ) + I->label = ON_ON; + + if ( ( (Q_m_type == IS_P_m) && (Q_p_type == RIGHT) ) || + ( (Q_p_type == IS_P_m) && (Q_m_type == RIGHT) ) ) + I->label = ON_LEFT; + + if ( ( (Q_m_type == IS_P_m) && (Q_p_type == LEFT) ) || + ( (Q_p_type == IS_P_m) && (Q_m_type == LEFT) ) ) + I->label = ON_RIGHT; + } + + // 2) classify intersection chains + for (Polygon2d& P : PP) + for (Vertex* I : P.Vertices(INTERSECTION)) + { + + // start of an intersection chain ? + if (I->label == LEFT_ON || + I->label == RIGHT_ON) + { + + // remember status of the first chain vertex and vertex itself + RelativePositionType x; + if (I->label == LEFT_ON) + x = LEFT; + else + x = RIGHT; + Vertex* X = I; + + // proceed to end of intersection chain and mark all visited vertices as NONE + do { + I->label = NONE; + I = I->next; + } while (I->label == ON_ON); + + RelativePositionType y; + if (I->label == ON_LEFT) + y = LEFT; + else + y = RIGHT; + + // determine type of intersection chain + IntersectionLabel chainType; + if (x != y) + chainType = DELAYED_CROSSING; + else + chainType = DELAYED_BOUNCING; + + // mark both ends of an intersection chain with chainType (i.e., as DELAYED_*) + X->label = chainType; + I->label = chainType; + } + } + + // 3) copy labels from P to Q + // loop over intersection vertices of P + for (Polygon2d& P : PP) + for (Vertex* I : P.Vertices(INTERSECTION)) + I->neighbour->label = I->label; + + // 3.5) check for special cases + + set noIntersection[2]; + set identical[2]; + + for (int i=0; i<2; ++i) + { + Array* P_or_Q = &PP; // if i=0, then do it for P w.r.t. Q + Array* Q_or_P = &QQ; + + if (i==1) { // if i=1, then do it for Q w.r.t. P + P_or_Q = &QQ; + Q_or_P = &PP; + } + + // loop over all components of P (or Q) + for (Polygon2d& P : *P_or_Q) + if (P.noCrossingVertex(UNION)) + { + // P_ has no crossing vertex (but may have bounces or delayed bounces, except for UNION), + // hence it does not intersect with Q_or_P + noIntersection[i].insert(&P); // remember component, and ignore it later in step 4 + + // is P identical to some component of and Q_or_P? + if (P.allOnOn()) + { + identical[i].insert(&P); // -> remember for further processing below + } + else + { + // is P inside Q_or_P? + bool isInside = false; + auto p = P.getNonIntersectionPoint(); + for (Polygon2d& Q : *Q_or_P) + if ( Q.IsInside(p) ) + isInside = !isInside; + if (isInside ^ UNION) + RR.Append(P); // -> add P to the result + } + } + } + + // handle components of P that are identical to some component of Q + for (Polygon2d* P : identical[0]) + { + // is P a hole? + bool P_isHole = false; + for (Polygon2d& P_ : PP) + if ( ( P_.first.get() != P->first.get() ) && (P_.IsInside(*P->first)) ) + P_isHole = !P_isHole; + + for (Polygon2d* Q : identical[1]) + for (Vertex* V : Q->Vertices(ALL)) + if (V == P->first->neighbour) { // found Q that matches P + // is Q a hole? + bool Q_isHole = false; + for (Polygon2d& Q_ : QQ) + if ( ( Q_.first.get() != Q->first.get() ) && (Q_.IsInside(*Q->first)) ) + Q_isHole = !Q_isHole; + + // if P and Q are both holes or both are not holes + if (P_isHole == Q_isHole) + RR.Append(*P); // -> add P to the result + goto next_P; + } +next_P: ; + } + + // 4) set entry/exit flags + set split[2]; // split vertex candidates for P and Q + set crossing[2]; // CROSSING vertex candidates for P and Q + + for (int i=0; i<2; ++i) + { + Array* P_or_Q = &PP; // if i=0, then do it for P w.r.t. Q + Array* Q_or_P = &QQ; + + if (i==1) { // if i=1, then do it for Q w.r.t. P + P_or_Q = &QQ; + Q_or_P = &PP; + } + + // loop over all components of P (or Q) + for (Polygon2d& P : *P_or_Q) + { + + // ignore P if it does not intersect with Q_or_P (detected in step 3.5 above) + if(noIntersection[i].find(&P) != noIntersection[i].end()) + continue; + + // start at a non-intersection vertex of P + Vertex* V = P.getNonIntersectionVertex(); + + // check if it is inside or outside Q (or P) + // and set ENTRY/EXIT status accordingly + EntryExitLabel status = ENTRY; + for (Polygon2d& Q : *Q_or_P) + if (Q.IsInside(*V)) + ToggleLabel(status); + + // starting at V, loop over those vertices of P, that are either + // a crossing intersection or marked as ends of an intersection chain + bool first_chain_vertex = true; // needed for dealing with crossing chains + + for (Vertex* I : P.Vertices(INTERSECTION, V)) + { + // in the case of normal crossings, we... + if (I->label == CROSSING) + { + // mark vertex with current ENTRY/EXIT status + I->enex = status; + // toggle status from ENTRY to EXIT or vice versa + ToggleLabel(status); + } + + // identify split vertex candidates (INTERIOR bouncing vertices) + if ( (I->label == BOUNCING) && ((status == EXIT) ^ UNION) ) + split[i].insert(I); + + // + // in the case of a delayed crossing chain, we + // mark both end points of the chain with the current ENTRY/EXIT status, + // toggling the status only at the end last chain vertex, + // and, in case of a delayed EXIT crossing, the first vertex + // or, in case of a delayed ENTRY crossing, the last vertex, + // of the chain as CROSSING + // + if (I->label == DELAYED_CROSSING) + { + // mark vertex with current ENTRY/EXIT status + I->enex = status; + + if (first_chain_vertex) { // are we at the first vertex of a delayed crossing chain? + if ((status == EXIT) ^ UNION) + I->label = CROSSING; // mark first vertex as CROSSING + first_chain_vertex = false; + } + else { // here we are at the last vertex of a delayed crossing chain + if ((status == ENTRY) ^ UNION) + I->label = CROSSING; // mark last vertex as CROSSING + first_chain_vertex = true; + + // toggle status from ENTRY to EXIT or vice versa (only for last chain vertex) + ToggleLabel(status); + } + } + + // + // in the case of a delayed bouncing chain, we + // mark both end points of the chain with the current ENTRY/EXIT status + // toggling the status at both end points of the chain, + // and, in case of a delayed INTERIOR bouncing, both end points + // of the chain as CROSSING candidates + // + if (I->label == DELAYED_BOUNCING) + { + // mark vertex with current ENTRY/EXIT status + I->enex = status; + + if (first_chain_vertex) { // are we at the first vertex of a delayed crossing chain? + if ((status == EXIT) ^ UNION) + crossing[i].insert(I); // mark first EXIT vertex as CROSSING candidate + first_chain_vertex = false; + } + else { // here we are at the last vertex of a delayed crossing chain + if ((status == ENTRY) ^ UNION) + crossing[i].insert(I); // mark last ENTRY vertex as CROSSING candidate + first_chain_vertex = true; + + } + // toggle status from ENTRY to EXIT or vice versa (for first AND last chain vertex) + ToggleLabel(status); + } + } + } + } + + // 5) handle split vertex pairs + // loop over P's split candidates + for (Vertex* I_P : split[0]) + { + Vertex* I_Q = I_P->neighbour; + + // check if the neighbour on Q is also a split candidate + if (split[1].find(I_Q) != split[1].end()) + { + // compute areas to compare local orientation + double sP = Area( *I_P->prev, *I_P, *I_P->next); + double sQ = Area( *I_Q->prev, *I_Q, *I_Q->next); + + // add duplicate vertices to P and Q + auto V_P = I_P->Insert(*I_P); + V_P->spline = I_P->spline; + auto V_Q = I_Q->Insert(*I_Q); + V_Q->spline = I_Q->spline; + + // link vertices correctly + if (sP*sQ > 0) { // same local orientation + I_P->Link( V_Q); + I_Q->Link( V_P); + } + else { // different local orientation + V_P->Link( V_Q); + } + + // mark all four vertices correctly + if (!UNION) + { + I_P->enex = EXIT; + V_P->enex = ENTRY; + I_Q->enex = EXIT; + V_Q->enex = ENTRY; + } + else + { + I_P->enex = ENTRY; + V_P->enex = EXIT; + I_Q->enex = ENTRY; + V_Q->enex = EXIT; + } + + I_P->label = CROSSING; + V_P->label = CROSSING; + I_Q->label = CROSSING; + V_Q->label = CROSSING; + } + } + + // 6) handle CROSSING vertex candidates + // loop over P's CROSSING candidates + for (Vertex* I_P : crossing[0]) + { + Vertex* I_Q = I_P->neighbour; + + // check if the neighbour on Q is also a CROSSING candidate + if (crossing[1].find(I_Q) != crossing[1].end()) + { + // mark CROSSING candidate pair as such + I_P->label = CROSSING; + I_Q->label = CROSSING; + } + } +} + +void CreateResult(Solid2d & sp, Solid2d & sr, bool UNION) +{ + auto & PP = sp.polys; + auto & RR = sr.polys; + // + // for all crossing vertices + // + // NOTE: all crossing vertices that are visited while contructing a + // component of the result polygon are marked as "not intersection", + // so that they cannot serve as start vertex of another component + // + + for (Polygon2d& P : PP) + { + for (Vertex* I : P.Vertices(CROSSING_INTERSECTION)) + { + Polygon2d R; // result polygon component + + Vertex* V = I; // start traversal at I + V->is_intersection = false; // mark visited vertices + + do { + EntryExitLabel status = V->enex; + ToggleLabel(status); + while ( !(V->enex == status)) // ... we arrive at a vertex with opposite entry/exit flag, or + { + auto & vnew = R.AppendVertex(*V); + if ((status == EXIT) ^ UNION) + { + vnew.bc = V->bc; + if(V->spline) + vnew.spline = *V->spline; + else + vnew.spline = nullopt; + V = V->next; // move forward from an ENTRY vertex to the next EXIT vertex + V->is_intersection = false; // mark visited vertices + } + else + { + V = V->prev; // move backward from an EXIT vertex to the next ENTRY vertex + if(V->spline) + { + auto & s = *V->spline; + vnew.spline = Spline{s.EndPI(), s.TangentPoint(), s.StartPI(), s.GetWeight()}; + } + else + vnew.spline = nullopt; + vnew.bc = V->bc; + V->is_intersection = false; // mark visited vertices + } + if(V == I) + break; + } + + if (V != I) + { + V = V->neighbour; // switch from P to Q or vice versa + V->is_intersection = false; // mark visited vertices + } + } while (V != I); // the result polygon component is complete, + // if we are back to the initial vertex I + RR.Append(R); + } + } +} + +void CleanUpResult(Solid2d & sr) +{ + auto & RR = sr.polys; + for (Polygon2d& R : RR) + { + while ( (R.first.get() != NULL) && (fabs(Area(*R.first->prev,*R.first,*R.first->next)) < EPSILON) ) + R.Remove(R.first.get()); + + if (R.first.get() != NULL) + for (Vertex* V : R.Vertices(ALL)) + if (!V->spline && !V->prev->spline && fabs(Area(*V->prev,*V,*V->next)) < EPSILON) + { + R.Remove(V); + } + } + for (int i = RR.Size()-1; i>=0; i--) + if(RR[i].Size()==0) + RR.RemoveElement(i); +} + +void RemoveDuplicates(Solid2d & sr) +{ + for(auto & poly : sr.polys) + { + if(poly.first==nullptr) continue; + Vertex * last = poly.first->prev; + for(auto v : poly.Vertices(ALL)) + { + if(Dist2(*v, *last) ps[] = + { + {x+r, y+0}, + {x+r, y+r}, + {x+0, y+r}, + {x-r, y+r}, + {x-r, y+0}, + {x-r, y-r}, + {x+0, y-r}, + {x+r, y-r} + }; + + for (auto i : IntRange(4)) + { + int i0 = 2*i; + int i1 = (i0+1)%8; + int i2 = (i0+2)%8; + auto & v0 = poly.Append( ps[i0] ); + v0.spline = { ps[i0], ps[i1], ps[i2] }; + } + + s.polys.Append(poly); + s.SetBC(bc); + return s; +} + +Solid2d AddIntersectionPoints ( Solid2d s1, Solid2d s2 ) +{ + ComputeIntersections(s1, s2); + RemoveDuplicates(s1); + return s1; +} + +Solid2d ClipSolids ( Solid2d s1, Solid2d s2, bool intersect) +{ + static Timer t1("intersection"); + static Timer t2("label"); + static Timer t3("cut"); + static Timer t4("cleanup"); + + for(auto & poly : s1.polys) + for(auto v : poly.Vertices(ALL)) + { + v->is_source = true; + v->neighbour = nullptr; + v->lam = -1.0; + v->is_intersection = false; + v->label = NONE; + v->enex = NEITHER; + } + + for(auto & poly : s2.polys) + for(auto v : poly.Vertices(ALL)) + { + v->is_source = true; + v->neighbour = nullptr; + v->lam = -1.0; + v->is_intersection = false; + v->label = NONE; + v->enex = NEITHER; + } + + Solid2d res; + res.name = s1.name; + + t1.Start(); + ComputeIntersections(s1, s2); + t1.Stop(); + + t2.Start(); + LabelIntersections(s1, s2, res, !intersect); + t2.Stop(); + + t3.Start(); + CreateResult(s1, res, !intersect); + t3.Stop(); + + t4.Start(); + CleanUpResult(res); + RemoveDuplicates(res); + t4.Stop(); + + return res; +} + +Solid2d Solid2d :: operator+(Solid2d & other) +{ + if(polys.Size()==0) + return other; + + auto res = ClipSolids(*this, other, false); + res.name = name; + return res; +} + +Solid2d Solid2d :: operator*(Solid2d & other) +{ + auto res = ClipSolids(*this, other, true); + res.name = name; + return res; +} + +Solid2d Solid2d :: operator-(Solid2d other) +{ + // TODO: Check dimensions of solids with bounding box + other.Append(RectanglePoly(-1e8, 1e8, -1e8, 1e8, "JUST_FOR_CLIPPING")); + auto res = ClipSolids(*this, other); + + for (auto i : Range(other.polys)) + { + auto & first = *other.polys[i].first; + if(first[0] == -1e8) + other.polys.DeleteElement(i); + } + res.name = name; + return res; +} + +bool Solid2d :: IsInside( Point<2> r ) const +{ + int w = 0; + for(auto & poly : polys) + for(auto v : poly.Vertices(ALL)) + w += CalcSide(*v, *v->next, r); + return ( (w % 2) != 0 ); +} + +bool Solid2d :: IsLeftInside( const Vertex & p0 ) +{ + auto & p1 = *p0.next; + auto v = p1-p0; + auto n = Vec<2>{v[1], -v[0]}; + auto q = p0 + 0.5*v + 1e-6*n; + return IsInside(q); +} + +bool Solid2d :: IsRightInside( const Vertex & p0 ) +{ + auto & p1 = *p0.next; + auto v = p1-p0; + auto n = Vec<2>{-v[1], v[0]}; + auto q = p0 + 0.5*v + 1e-6*n; + return IsInside(q); +} + + +shared_ptr CSG2d :: GenerateSplineGeometry() +{ + static Timer t_intersections("CSG2d - AddIntersections()"); + static Timer tall("CSG2d - GenerateSplineGeometry()"); + RegionTimer rt(tall); + + struct Seg + { + int p0; + int p1; + int left; + int right; + int bc; + int p2; + double weight; + }; + + auto geo = std::make_shared(); + std::map, Seg> seg_map; + std::map bcmap; + Array points; + + // Cut each solid with each other one to add all possible intersection points and have conforming edges from both domains + // TODO: OPTIMIZE!!! + // Idea: Find edges with just one neighbor (either leftdomain or rightdomain unset after the marking below) -> just cut those edges with each other + t_intersections.Start(); + for(auto & s1 : solids) + for(auto & s2 : solids) + if(&s1!=&s2) + s1 = AddIntersectionPoints(s1,s2); + t_intersections.Stop(); + + // Add geometry points to SplineGeometry + + netgen::Box<2> box; + for(auto & s : solids) + for(auto & poly : s.polys) + for(auto v : poly.Vertices(ALL)) + box.Add(*v); + + netgen::BoxTree <2, int> ptree(box); + + auto getPoint = [&](Point<2> p ) + { + int res = -1; + ptree.GetFirstIntersecting(p, p, [&] (int pi) + { + res = pi; + return true; + }); + return res; + }; + + auto insertPoint = [&](Point<2> p ) + { + int pi = getPoint(p); + if(pi==-1) + { + // not found -> insert to tree + netgen::GeomPoint<2> gp(p); + gp.name = ""; + geo->geompoints.Append(gp); + ptree.Insert(p,p,geo->geompoints.Size()-1); + } + }; + + for(auto & s : solids) + for(auto & poly : s.polys) + for(auto v : poly.Vertices(ALL)) + { + box.Add(*v); + insertPoint(*v); + if(v->spline) + insertPoint(v->spline->TangentPoint()); + } + + + // Generate segments from polygon edges and find left/right domain of each segment + int dom = 0; + for(auto & s : solids) + { + dom++; + geo->SetMaterial(dom, s.name); + for(auto & poly : s.polys) + { + for(auto v : poly.Vertices(ALL)) + { + auto & p0 = *v; + auto & p1 = *v->next; + + auto pi0 = getPoint(p0); + auto pi1 = getPoint(p1); + int pi2 = -1; + double weight = 0.0; + + if(v->spline) + { + auto p2 = v->spline->TangentPoint(); + pi2 = getPoint(p2); + weight = v->spline->GetWeight(); + } + + bool flip = false; + if(pi1SetBCName(bc, name); + } + + for(auto const &m : seg_map) + { + auto ls = m.second; + netgen::SplineSegExt * seg; + if(ls.p2!=-1) + { + // spline segment + auto * seg3 = new netgen::SplineSeg3<2>( geo->GetPoint(ls.p0), geo->GetPoint(ls.p2), geo->GetPoint(ls.p1), ls.weight ); + seg = new netgen::SplineSegExt(*seg3); + } + else + { + // line segment + auto * l = new netgen::LineSeg<2>(geo->GetPoint(ls.p0), geo->GetPoint(ls.p1)); + seg = new netgen::SplineSegExt(*l); + } + + seg->leftdom = ls.left; + seg->rightdom = ls.right; + seg->bc = ls.bc; + seg->reffak = 1; + seg->copyfrom = -1; + seg->hmax = 1e99; + geo->AppendSegment(seg); + } + return geo; +} +} diff --git a/libsrc/geom2d/csg2d.hpp b/libsrc/geom2d/csg2d.hpp new file mode 100644 index 00000000..0adc1216 --- /dev/null +++ b/libsrc/geom2d/csg2d.hpp @@ -0,0 +1,583 @@ +#ifndef NETGEN_CSG2D_HPP_INCLUDED +#define NETGEN_CSG2D_HPP_INCLUDED + +#include "geometry2d.hpp" + +namespace netgen +{ + +using namespace ngcore; +using netgen::Point; +using netgen::Vec; + +inline double Area(const Point<2>& P, const Point<2>& Q, const Point<2>& R) +{ + return (Q[0]-P[0]) * (R[1]-P[1]) - (Q[1]-P[1]) * (R[0]-P[0]); +} + + +enum IntersectionType +{ // types of intersection (detected in the first phase) + NO_INTERSECTION = 0, + X_INTERSECTION, + T_INTERSECTION_Q, + T_INTERSECTION_P, + V_INTERSECTION, + X_OVERLAP, + T_OVERLAP_Q, + T_OVERLAP_P, + V_OVERLAP +}; + +enum IntersectionLabel +{ // for the classification of intersection vertices in the second phase + NONE, + CROSSING, + BOUNCING, + LEFT_ON, + RIGHT_ON, + ON_ON, + ON_LEFT, + ON_RIGHT, + DELAYED_CROSSING, + DELAYED_BOUNCING +}; + +enum EntryExitLabel +{ // for marking intersection vertices as "entry" or "exit" + EXIT, + ENTRY, + NEITHER +}; + +enum IteratorType +{ + SOURCE, + INTERSECTION, + CROSSING_INTERSECTION, + ALL +}; + + +using Spline = SplineSeg3<2>; + +struct Vertex : Point<2> +{ + Vertex (Point<2> p) : Point<2>(p) {} + + Vertex * prev = nullptr; + Vertex * next = nullptr; + unique_ptr pnext = nullptr; + Vertex * neighbour = nullptr; // same vertex in other polygon (at intersections) + double lam = -1.0; + bool is_intersection = false; + bool is_source = false; + + IntersectionLabel label = NONE; // type of intersection vertex + EntryExitLabel enex = NEITHER; // entry/exit "flag" + + string bc = ""; + + // In case the edge this - next is curved, store the spline information here + optional spline = nullopt; + + Vertex * Insert(Point<2> p, double lam = -1.0); + + void Link( Vertex * v ) + { + neighbour = v; + v->neighbour = this; + is_intersection = true; + v->is_intersection = true; + } +}; + +struct VertexIterator +{ + struct iterator + { + iterator(Vertex* root, IteratorType IterType) : + root(root), V(NULL), iterType(IterType) + { + if (root == NULL) + return; + + if (nextVertex() == NULL) // no (source/intersection) vertex found + root = V = NULL; // -> mark iterator as "end" + } + + const iterator& operator++() + { + nextVertex(); + return *this; + } + + Vertex* operator*() + { + return V; + } + + bool operator!=(const iterator& other) const + { + return (root != other.root) || (V != other.V); + } + + private: + Vertex* root; + Vertex* V; + IteratorType iterType; + + // + // find the next vertex + // if iterType is ALL, then it is just the next vertex + // if iterType is SOURCE, then it is the next source vertex + // if iterType is INTERSECTION, then it is the next intersection vertex + // if iterType is CROSSING_INTERSECTION, then it is the next intersection vertex with CROSSING label + // + Vertex* nextVertex() + { + bool nextFound = false; + + if (V == NULL) + { // find first (source/intersection) vertex + V = root; + switch(iterType) + { + case ALL: + nextFound = true; + break; + case SOURCE: + if (V->is_source) + nextFound = true; + break; + case INTERSECTION: + if (V->is_intersection) + nextFound = true; + break; + case CROSSING_INTERSECTION: + if (V->is_intersection && (V->label == CROSSING)) + nextFound = true; + break; + } + } + + while (!nextFound) + { // find next (source/intersection) vertex + switch(iterType) + { + case ALL: + V = V->next; + break; + case SOURCE: + do { + V = V->next; + } while (!V->is_source && V != root); + break; + case INTERSECTION: + do { + V = V->next; + } while (!V->is_intersection && V != root); + break; + case CROSSING_INTERSECTION: + do { + V = V->next; + } while ( ( !V->is_intersection || (V->label != CROSSING) ) && V != root); + break; + } + + if (V == root) + { // back at the root vertex? + root = V = NULL; // -> mark iterator as "end" + return(V); + } + + switch(iterType) + { + case ALL: + nextFound = true; + break; + case SOURCE: + if (V->is_source) + nextFound = true; + break; + case INTERSECTION: + if (V->is_intersection) + nextFound = true; + break; + case CROSSING_INTERSECTION: + if (V->is_intersection && (V->label == CROSSING)) + nextFound = true; + break; + } + } + return(V); + } + }; + + public: + VertexIterator() : root(NULL) {}; + + iterator begin() { return iterator(root, iterType); } + iterator end() { return iterator(NULL, iterType); } + + Vertex* root; + IteratorType iterType; +}; + + +struct Edge +{ + Vertex * v0 = nullptr; + Vertex * v1 = nullptr; + + Edge (Vertex* v, Vertex* w) : v0(v), v1(w) { }; +}; + +struct EdgeIterator +{ + struct iterator + { + iterator(Vertex* root, IteratorType IterType) : + root(root), one(NULL), two(NULL), iterType(IterType) + { + if (root == NULL) + return; + + if (nextEdge() == NULL) // no source edge found + root = one = two = NULL; // -> mark iterator as "end" + } + + const iterator& operator++() { nextEdge(); return *this; } + + Edge operator*() + { + return Edge(one,two); + } + + bool operator!=(const iterator& other) const + { + return (root != other.root) || (one != other.one) || (two != other.two); + } + + private: + Vertex* root; + Vertex* one; + Vertex* two; + IteratorType iterType; + + // + // find the next vertex, starting at curr + // if iterType is ALL, then it is just the next vertex + // if iterType is SOURCE, then it is the next source vertex + // + Vertex* nextVertex(Vertex* curr) + { + if (curr == NULL) + return(NULL); + + switch(iterType) + { + case ALL: + curr = curr->next; + break; + + case SOURCE: + do { + curr = curr->next; + } while (!curr->is_source); + break; + default: + ; + } + + return(curr); + } + + // + // find the next edge + // + Vertex* nextEdge() + { + if (root == NULL) // empty polygon? + return (NULL); + + if (one == NULL) + { // find one (source) vertex + one = root; // note: root is always a (source) vertex + two = nextVertex(one); + if (two == one) // just one (source) vertex + return(NULL); // -> no (source) edges + return(one); + } + + if (two == root) + { // back at the root vertex? + root = one = two = NULL; // -> mark iterator as "end" + return(NULL); + } + + one = two; + two = nextVertex(one); + + return (one); + } + }; + + public: + EdgeIterator() : root(NULL) {}; + + iterator begin() { return iterator(root, iterType); } + iterator end() { return iterator(NULL, iterType); } + + Vertex* root; + IteratorType iterType; +}; + + +inline int CalcSide( const Point<2> & p0, const Point<2> & p1, const Point<2> & r ) +{ + if ( (p0[1] < r[1]) != (p1[1] < r[1]) ) + { + if (p0[0] >= r[0]) + { + if (p1[0] > r[0]) + return 2 * (p1[1] > p0[1]) - 1; + else + if ( (Area(p0,p1,r) > 0) == (p1[1] > p0[1]) ) + return 2 * (p1[1] > p0[1]) - 1; + } + else + { + if (p1[0] > r[0]) + if ( (Area(p0,p1,r) > 0) == (p1[1] > p0[1]) ) + return 2 * (p1[1] > p0[1]) - 1; + } + } + return 0; +} + +struct Polygon2d +{ + unique_ptr first = nullptr; + + Polygon2d() = default; + + Polygon2d(const Polygon2d & p) + : first(nullptr) + { + for(auto v : p.Vertices(ALL)) + AppendVertex(*v); + } + + Polygon2d & operator=(const Polygon2d & p) + { + first = nullptr; + if(p.first) + for(const auto v : p.Vertices(ALL)) + AppendVertex(*v); + return *this; + } + + Vertex & AppendVertex(const Vertex & v) + { + auto & vnew = Append( static_cast>(v), true ); + vnew.bc = v.bc; + if(v.spline) + vnew.spline = *v.spline; + return vnew; + } + + Vertex & Append(Point<2> p, bool source = false) + { + Vertex * vnew; + if(first==nullptr) + { + first = make_unique(p); + first->next = first.get(); + first->prev = first.get(); + vnew = first.get(); + } + else + { + vnew = first->prev->Insert(p); + } + + vnew->is_source = source; + // cout << "size after " << Size() << endl; + return *vnew; + } + + void Remove (Vertex* v) + { + v->prev->next = v->next; + v->next->prev = v->prev; + if(first.get() == v) + first = std::move(v->pnext); + else + v->prev->pnext = std::move(v->pnext); + } + + bool IsInside( Point<2> r ) const + { + int w = 0; + for(auto e : Edges(ALL)) + w += CalcSide(*e.v0, *e.v1, r); + return ( (w % 2) != 0 ); + } + + EdgeIterator Edges(IteratorType iterType) const + { + EdgeIterator it; + it.iterType = iterType; + it.root = first.get(); + return it; + } + + VertexIterator Vertices(IteratorType iterType, Vertex* first_ = nullptr) const + { + VertexIterator it; + it.iterType = iterType; + it.root = (first_ == nullptr) ? first.get() : first_; + return it; + } + + // + // check, if all vertices have the ON_ON label + // + bool allOnOn() + { + for (Vertex* v : Vertices(ALL)) + if (v->label != ON_ON) + return(false); + return(true); + } + + // + // check, if the polygon does not contain any crossing intersection vertex + // or crossing intersection chain or (if we want to compute the union instead + // of the intersection) a bouncing vertex or a bouncing intersection chain + // + bool noCrossingVertex(bool union_case = false) + { + for (Vertex* v : Vertices(ALL)) + if (v->is_intersection) + { + if ( (v->label == CROSSING) || (v->label == DELAYED_CROSSING) ) + return(false); + + if (union_case && ( (v->label == BOUNCING) || (v->label == DELAYED_BOUNCING) ) ) + return(false); + } + return(true); + } + + // + // return a non-intersection point + // + Point<2> getNonIntersectionPoint() + { + for (Vertex* v : Vertices(ALL)) + if (!v->is_intersection) + return *v; + + // no non-intersection vertex found -> find suitable edge midpoint + for (Vertex* v : Vertices(ALL)) + // make sure that edge from V to V->next is not collinear with other polygon + if ( (v->next->neighbour != v->neighbour->prev) && (v->next->neighbour != v->neighbour->next) ) + // return edge midpoint + return Center(*v, *v->next); + throw Exception("no point found"); + } + + // + // return and insert a non-intersection vertex + // + Vertex* getNonIntersectionVertex() + { + for (Vertex* v : Vertices(ALL)) + if (!v->is_intersection) + return(v); + + // no non-intersection vertex found -> generate and return temporary vertex + for (Vertex* v : Vertices(ALL)) + // make sure that edge from V to V->next is not collinear with other polygon + if ( (v->next->neighbour != v->neighbour->prev) && (v->next->neighbour != v->neighbour->next) ) + { + // add edge midpoint as temporary vertex + auto p = Center(*v, *v->next); + return v->Insert(p); + } + return(NULL); + } + + void SetBC(string bc) + { + for(auto v : Vertices(ALL)) + v->bc = bc; + } + + size_t Size() const + { + if(first==nullptr) return 0; + + size_t cnt = 0; + + for(auto v : Vertices(ALL)) + cnt++; + + return cnt; + } +}; + + +struct Solid2d +{ + Array polys; + + string name = ""; + + Solid2d() = default; + Solid2d(string name_) : name(name_) {} + + Solid2d operator+(Solid2d & other); + Solid2d operator*(Solid2d & other); + Solid2d operator-(Solid2d other); + + void Append( const Polygon2d & poly ) + { + polys.Append(poly); + } + + bool IsInside( Point<2> r ) const; + bool IsLeftInside( const Vertex & p0 ); + bool IsRightInside( const Vertex & p0 ); + + void SetBC(string bc) + { + for(auto & p : polys) + for(auto v : p.Vertices(ALL)) + v->bc = bc; + } +}; + +class CSG2d +{ + public: + Array solids; + + void Add ( Solid2d s ) + { + solids.Append(s); + } + + shared_ptr GenerateSplineGeometry(); +}; + +Solid2d Circle(double x, double y, double r, string name="", string bc=""); +Solid2d Rectangle(double x0, double x1, double y0, double y1, string name="", string bc=""); + +Solid2d AddIntersectionPoints ( Solid2d s1, Solid2d s2 ); +Solid2d ClipSolids ( Solid2d s1, Solid2d s2, bool intersect=true ); + +} +#endif // NETGEN_CSG2D_HPP_INCLUDED diff --git a/libsrc/geom2d/geometry2d.hpp b/libsrc/geom2d/geometry2d.hpp index f5841b19..c7f59824 100644 --- a/libsrc/geom2d/geometry2d.hpp +++ b/libsrc/geom2d/geometry2d.hpp @@ -9,6 +9,7 @@ #include #include +#include // #include "../gprim/spline.hpp" diff --git a/libsrc/geom2d/python_geom2d.cpp b/libsrc/geom2d/python_geom2d.cpp index f591e74e..f3f83f57 100644 --- a/libsrc/geom2d/python_geom2d.cpp +++ b/libsrc/geom2d/python_geom2d.cpp @@ -6,6 +6,7 @@ #include #include +#include using namespace netgen; @@ -265,6 +266,7 @@ DLL_HEADER void ExportGeom2d(py::module &m) { double len = self.splines[i]->Length(); int n = floor(len/(0.05*min(xdist,ydist))); + n = max(3, n); lst.push_back(self.splines[i]->StartPI()); for (int j = 1; j < n; j++){ lst.push_back(self.splines[i]->GetPoint(j*1./n)); @@ -395,6 +397,36 @@ DLL_HEADER void ExportGeom2d(py::module &m) .def("_SetDomainTensorMeshing", &SplineGeometry2d::SetDomainTensorMeshing) ; + py::class_(m, "Solid2d") + .def(py::init<>()) + .def(py::init()) + .def_readwrite("name", &Solid2d::name) + .def("__mul__", [](Solid2d & self, Solid2d & other) { return self*other; }) + .def("__add__", [](Solid2d & self, Solid2d & other) { return self+other; }) + .def("__sub__", [](Solid2d & self, Solid2d & other) { return self-other; }) + .def("Append", &Solid2d::Append) + .def("SetBC", &Solid2d::SetBC) + ; + + py::class_(m, "Polygon2d") + .def(py::init<>()) + .def("SetBC", &Polygon2d::SetBC) + .def("Append", [](Polygon2d & self, double x, double y) + { + self.Append({x,y}); + }) + ; + + + m.def("Rectangle", &Rectangle); + m.def("Circle", &Circle); + + py::class_(m, "CSG2d") + .def(py::init<>()) + .def("GenerateSplineGeometry", &CSG2d::GenerateSplineGeometry) + .def("Add", &CSG2d::Add) + ; + } PYBIND11_MODULE(libgeom2d, m) { diff --git a/libsrc/gprim/geom2d.cpp b/libsrc/gprim/geom2d.cpp index 34263348..7d051359 100644 --- a/libsrc/gprim/geom2d.cpp +++ b/libsrc/gprim/geom2d.cpp @@ -251,239 +251,4 @@ int PTRIANGLE2D :: IsIn (const Point2d & p) const } #endif - - - - - - -Polygon2d :: Polygon2d () -{ - ; -} - -Polygon2d :: ~Polygon2d () -{ - ; -} - -void Polygon2d :: AddPoint (const Point2d & p) -{ - points.Append(p); -} - - -double Polygon2d :: HArea () const -{ - int i; - double ar = 0; - for (i = 1; i <= points.Size(); i++) - { - const Point2d & p1 = points.Get(i); - const Point2d & p2 = points.Get(i%points.Size()+1); - ar += - (p2.X()-p1.X()) * p1.Y() - - (p2.Y()-p1.Y()) * p1.X(); - } - return ar/2; - /* - CURSOR c; - double ar = 0; - Point2d * p1, * p2, p0 = Point2d(0, 0); - Vec2d v1, v2 = Vec2d(1, 0); - - p2 = points[points.Last()]; - for (c = points.First(); c != points.Head(); c++) - { - p1 = p2; - p2 = points[c]; - ar += Cross ( (*p2-*p1), (*p1 - p0)); - } - return ar / 2; - */ -} - - -int Polygon2d :: IsOn (const Point2d & p) const -{ - int i; - for (i = 1; i <= points.Size(); i++) - { - const Point2d & p1 = points.Get(i); - const Point2d & p2 = points.Get(i%points.Size()+1); - if (IsOnLine (Line2d(p1, p2), p)) return 1; - } - return 0; - /* - CURSOR c; - Point2d * p1, * p2; - - p2 = points[points.Last()]; - for (c = points.First(); c != points.Head(); c++) - { - p1 = p2; - p2 = points[c]; - if (IsOnLine (Line2d(*p1, *p2), p)) return 1; - } - return 0; - */ -} - - -int Polygon2d :: IsIn (const Point2d & p) const -{ - int i; - double sum = 0, ang; - for (i = 1; i <= points.Size(); i++) - { - const Point2d & p1 = points.Get(i); - const Point2d & p2 = points.Get(i%points.Size()+1); - ang = Angle ( (p1 - p), (p2 - p) ); - if (ang > M_PI) ang -= 2 * M_PI; - sum += ang; - } - return fabs(sum) > M_PI; - /* - CURSOR c; - Point2d * p1, * p2; - double sum = 0, ang; - - p2 = points[points.Last()]; - for (c = points.First(); c != points.Head(); c++) - { - p1 = p2; - p2 = points[c]; - ang = Angle ( (*p1 - p), (*p2 - p) ); - if (ang > M_PI) ang -= 2 * M_PI; - sum += ang; - } - - return fabs(sum) > M_PI; - */ -} - -int Polygon2d :: IsConvex () const - { - /* - Point2d *p, *pold, *pnew; - char cw; - CURSOR c; - - if (points.Length() < 3) return 0; - - c = points.Last(); - p = points[c]; - c--; - pold = points[c]; - pnew = points[points.First()]; - cw = ::CW (*pold, *p, *pnew); - - for (c = points.First(); c != points.Head(); c++) - { - pnew = points[c]; - if (cw != ::CW (*pold, *p, *pnew)) - return 0; - pold = p; - p = pnew; - } - */ - return 0; - } - - -int Polygon2d :: IsStarPoint (const Point2d & p) const - { - /* - Point2d *pnew, *pold; - char cw; - CURSOR c; - - if (points.Length() < 3) return 0; - - pold = points[points.Last()]; - pnew = points[points.First()]; - - cw = ::CW (p, *pold, *pnew); - - for (c = points.First(); c != points.Head(); c++) - { - pnew = points[c]; - if (cw != ::CW (p, *pold, *pnew)) - return 0; - pold = pnew; - } - return 1; - */ - return 0; - } - - -Point2d Polygon2d :: Center () const - { - /* - double ai, a = 0, x = 0, y = 0; - Point2d * p, *p2; - Point2d p0 = Point2d(0, 0); - CURSOR c; - - p2 = points[points.Last()]; - - for (c = points.First(); c != points.Head(); c++) - { - p = points[c]; - ai = Cross (*p2 - p0, *p - p0); - x += ai / 3 * (p2->X() + p->X()); - y += ai / 3 * (p2->Y() + p->Y()); - a+= ai; - p2 = p; - } - if (a != 0) - return Point2d (x / a, y / a); - else - return Point2d (0, 0); - */ - return Point2d (0, 0); - } - - - -Point2d Polygon2d :: EqualAreaPoint () const - { - /* - double a11 = 0, a12 = 0, a21= 0, a22 = 0; - double b1 = 0, b2 = 0, dx, dy; - double det; - Point2d * p, *p2; - CURSOR c; - - p = points[points.Last()]; - - for (c = points.First(); c != points.Head(); c++) - { - p2 = p; - p = points[c]; - - dx = p->X() - p2->X(); - dy = p->Y() - p2->Y(); - - a11 += sqr (dy); - a12 -= dx * dy; - a21 -= dx * dy; - a22 += sqr (dx); - b1 -= dy * (p->X() * p2->Y() - p2->X() * p->Y()); - b2 -= dx * (p->Y() * p2->X() - p2->Y() * p->X()); - } - - det = a11 * a22 - a21 * a12; - - if (det != 0) - return Point2d ( (b1 * a22 - b2 * a12) / det, - (a11 * b2 - a21 * b1) / det); - else - return Point2d (0, 0); -*/ - return Point2d (0, 0); - } - - } diff --git a/libsrc/gprim/geom2d.hpp b/libsrc/gprim/geom2d.hpp index b86c74b7..890a456b 100644 --- a/libsrc/gprim/geom2d.hpp +++ b/libsrc/gprim/geom2d.hpp @@ -609,40 +609,6 @@ namespace netgen #endif - - class Polygon2d - { - protected: - NgArray points; - - public: - Polygon2d (); - ~Polygon2d (); - - void AddPoint (const Point2d & p); - int GetNP() const { return points.Size(); } - void GetPoint (int i, Point2d & p) const - { p = points.Get(i); } - void GetLine (int i, Point2d & p1, Point2d & p2) const - { p1 = points.Get(i); p2 = points.Get(i%points.Size()+1); } - - double Area () const { return fabs (HArea()); } - int CW () const { return HArea() > 0; } - int CCW () const { return HArea() < 0; } - - int IsOn (const Point2d & p) const; - int IsIn (const Point2d & p) const; - - int IsConvex () const; - - int IsStarPoint (const Point2d & p) const; - Point2d Center() const; - Point2d EqualAreaPoint () const; - private: - double HArea () const; - }; - - /** Cheap approximation to atan2. A monotone function of atan2(x,y) is computed. */ diff --git a/libsrc/gprim/spline.hpp b/libsrc/gprim/spline.hpp index d2ba6f4e..b594f85b 100644 --- a/libsrc/gprim/spline.hpp +++ b/libsrc/gprim/spline.hpp @@ -196,6 +196,10 @@ namespace netgen { ar & p1 & p2 & p3 & weight & proj_latest_t; } + /// + double GetWeight () const { return weight; } + void SetWeight (double w) { weight = w; } + /// virtual Point GetPoint (double t) const; /// virtual Vec GetTangent (const double t) const; diff --git a/python/geom2d.py b/python/geom2d.py index c683e035..96152cc2 100644 --- a/python/geom2d.py +++ b/python/geom2d.py @@ -1,4 +1,4 @@ -from .libngpy._geom2d import SplineGeometry +from .libngpy._geom2d import SplineGeometry, Solid2d, Polygon2d, CSG2d, Rectangle, Circle from .meshing import meshsize unit_square = SplineGeometry() From 79ebf6eca16a9014f1790caf336a61467975a90d Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Wed, 19 Aug 2020 16:58:54 +0200 Subject: [PATCH 115/384] Add CSG2d tutorial --- py_tutorials/csg2d.py | 50 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 py_tutorials/csg2d.py diff --git a/py_tutorials/csg2d.py b/py_tutorials/csg2d.py new file mode 100644 index 00000000..369101f3 --- /dev/null +++ b/py_tutorials/csg2d.py @@ -0,0 +1,50 @@ +from ngsolve import * + +from random import random, seed +ngsglobals.msg_level = 0 + +import netgen +from pyngcore import * +from netgen.geom2d import * + +seed(4) + +def GenerateMesh(): + + g = CSG2d() + g1 = CSG2d() + outer = Rectangle(0, 1, 0, 1,"outer","outer") + inner = Solid2d() + + for i in range(30): + cx = random() + cy = random() + r = 0.03+0.05*random() + print("Add Circle", i, cx, cy, r, flush = True) + circle = Circle(cx, cy, r, "circle"+str(i), "circle"+str(i)) + g1.Add(circle) + inner += circle + outer -= circle + + + g.Add(inner) + g.Add(outer) + geo = g.GenerateSplineGeometry() + Draw(geo) + + # draw this geometry for checking ff the final mesh/geometry is correct + # g1.Add(outer) + # geo1 = g1.GenerateSplineGeometry() + # Draw(geo1) + + print('generate mesh') + m = geo.GenerateMesh(maxh=0.1) + mesh = Mesh(m) + mesh.Curve(3) + Draw(mesh) + + return mesh + +from ngsolve import Draw +with PajeTrace(): + mesh = GenerateMesh() From 7cbeca147a46f15fe661224d0be0d11a68ac9e06 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Wed, 19 Aug 2020 16:25:54 +0200 Subject: [PATCH 116/384] fix windows build --- libsrc/geom2d/csg2d.hpp | 2 +- libsrc/geom2d/python_geom2d.cpp | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/libsrc/geom2d/csg2d.hpp b/libsrc/geom2d/csg2d.hpp index 0adc1216..210c3d81 100644 --- a/libsrc/geom2d/csg2d.hpp +++ b/libsrc/geom2d/csg2d.hpp @@ -574,7 +574,7 @@ class CSG2d }; Solid2d Circle(double x, double y, double r, string name="", string bc=""); -Solid2d Rectangle(double x0, double x1, double y0, double y1, string name="", string bc=""); +Solid2d Rectangle(double x0, double x1, double y0, double y1, string name, string bc); Solid2d AddIntersectionPoints ( Solid2d s1, Solid2d s2 ); Solid2d ClipSolids ( Solid2d s1, Solid2d s2, bool intersect=true ); diff --git a/libsrc/geom2d/python_geom2d.cpp b/libsrc/geom2d/python_geom2d.cpp index f3f83f57..1875f6ba 100644 --- a/libsrc/geom2d/python_geom2d.cpp +++ b/libsrc/geom2d/python_geom2d.cpp @@ -418,8 +418,11 @@ DLL_HEADER void ExportGeom2d(py::module &m) ; - m.def("Rectangle", &Rectangle); - m.def("Circle", &Circle); + m.def("Rectangle", [](double x0, double x1, double y0, double y1, string bc, string mat) + { return Rectangle(x0,x1,y0,y1,bc,mat); }, + py::arg("x0"), py::arg("x1"), py::arg("y0"), py::arg("y1"), py::arg("bc")="", py::arg("mat")="" + ); + m.def("Circle", Circle, py::arg("x"), py::arg("y"), py::arg("r"), py::arg("bc")="", py::arg("mat")=""); py::class_(m, "CSG2d") .def(py::init<>()) From 2c6e0e2becc56fa96dda2a99d00d8cefa3b2a025 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20Sch=C3=B6berl?= Date: Wed, 19 Aug 2020 19:28:34 +0200 Subject: [PATCH 117/384] global enumeration of points for pickling (as an option) --- libsrc/meshing/meshclass.cpp | 96 +++++++++++++++++++++++++++++++++++- libsrc/meshing/meshtype.hpp | 1 + 2 files changed, 96 insertions(+), 1 deletion(-) diff --git a/libsrc/meshing/meshclass.cpp b/libsrc/meshing/meshclass.cpp index dc2097b8..5b859931 100644 --- a/libsrc/meshing/meshclass.cpp +++ b/libsrc/meshing/meshclass.cpp @@ -1289,13 +1289,107 @@ namespace netgen if (comm.Rank() == 0) archive & dimension; - // merge points + auto rank = comm.Rank(); + auto & partop = GetParallelTopology(); + + // global enumration of points: + // not used now, but will be needed for refined meshes + // GridFunciton pickling is not compatible, now + // should go to paralleltopology + + Array global_pnums(points.Size()); + global_pnums = -1; + int num_master_points = 0; + for (PointIndex pi : Range(points)) + { + auto distprocs = partop.GetDistantPNums(pi-PointIndex::BASE); + // check sorted: + for (int j = 0; j+1 < distprocs.Size(); j++) + if (distprocs[j+1] < distprocs[j]) cout << "wrong sort" << endl; + if (distprocs.Size() == 0 || distprocs[0] > comm.Rank()) + global_pnums[pi] = PointIndex::BASE+num_master_points++; + } + Array first_master_point(comm.Size()); + GetCommunicator().AllGather (num_master_points, first_master_point); + + size_t num_glob_points = 0; + for (int i = 0; i < comm.Size(); i++) + { + int cur = first_master_point[i]; + first_master_point[i] = num_glob_points; + num_glob_points += cur; + } + + for (PointIndex pi : Range(points)) + if (global_pnums[pi] != -1) + global_pnums[pi] += first_master_point[comm.Rank()]; + + // ScatterDofData (global_nums); + + Array nsend(comm.Size()), nrecv(comm.Size()); + nsend = 0; + nrecv = 0; + + /** Count send/recv size **/ + for (PointIndex pi : Range(points)) + { + auto dps = partop.GetDistantPNums(pi-PointIndex::BASE); + if (!dps.Size()) continue; + if (rank < dps[0]) + for(auto p:dps) + nsend[p]++; + else + nrecv[dps[0]]++; + } + + Table send_data(nsend); + Table recv_data(nrecv); + + /** Fill send_data **/ + nsend = 0; + for (PointIndex pi : Range(points)) + { + auto dps = partop.GetDistantPNums(pi-PointIndex::BASE); + if (dps.Size() && rank < dps[0]) + for(auto p : dps) + send_data[p][nsend[p]++] = global_pnums[pi]; + } + + Array requests; + for (int i = 0; i < comm.Size(); i++) + { + if (nsend[i]) + requests.Append (comm.ISend (send_data[i], i, 200)); + if (nrecv[i]) + requests.Append (comm.IRecv (recv_data[i], i, 200)); + } + + MyMPI_WaitAll (requests); + + Array cnt(comm.Size()); + cnt = 0; + + for (PointIndex pi : Range(points)) + { + auto distprocs = partop.GetDistantPNums(pi-PointIndex::BASE); + if (distprocs.Size() > 0 && distprocs[0] < comm.Rank()) + { + int master = comm.Size(); + for (int j = 0; j < distprocs.Size(); j++) + master = min (master, distprocs[j]); + global_pnums[pi] = recv_data[master][cnt[master]++]; + } + } + + + // merge points Array globnum(points.Size()); int maxglob = 0; for (auto pi : Range(points)) { globnum[pi] = partop.GetGlobalPNum(pi); + // globnum[pi] = global_pnums[pi]; maxglob = max(globnum[pi], maxglob); } diff --git a/libsrc/meshing/meshtype.hpp b/libsrc/meshing/meshtype.hpp index e38f7ad8..4071df4b 100644 --- a/libsrc/meshing/meshtype.hpp +++ b/libsrc/meshing/meshtype.hpp @@ -177,6 +177,7 @@ namespace netgen PointIndex operator-- (int) { PointIndex hi(*this); i--; return hi; } PointIndex & operator++ () { i++; return *this; } PointIndex operator-- () { i--; return *this; } + PointIndex operator+= (int add) { i += add; return *this; } void Invalidate() { i = PointIndex::BASE-1; } bool IsValid() const { return i != PointIndex::BASE-1; } #ifdef BASE0 From 28d4b219fa4332d116c94627aa77b251a5264cc2 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Thu, 20 Aug 2020 15:07:43 +0200 Subject: [PATCH 118/384] bugfix in csg2d --- libsrc/geom2d/csg2d.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsrc/geom2d/csg2d.cpp b/libsrc/geom2d/csg2d.cpp index 96bf07c5..e75710d3 100644 --- a/libsrc/geom2d/csg2d.cpp +++ b/libsrc/geom2d/csg2d.cpp @@ -719,7 +719,7 @@ RelativePositionType oracle(bool prev, Vertex* P1, Vertex* P2, Vertex* P3) { Q = P2->neighbour->next; q = *Q; - if(P2->spline) + if(P2->neighbour->spline) q = P2->neighbour->spline->TangentPoint(); } From 4dcd20a0c75384a896b38925a5f7f52216c798a3 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Thu, 20 Aug 2020 16:12:26 +0200 Subject: [PATCH 119/384] initialize bounding box --- libsrc/geom2d/csg2d.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsrc/geom2d/csg2d.cpp b/libsrc/geom2d/csg2d.cpp index e75710d3..b495d902 100644 --- a/libsrc/geom2d/csg2d.cpp +++ b/libsrc/geom2d/csg2d.cpp @@ -1417,7 +1417,7 @@ shared_ptr CSG2d :: GenerateSplineGeometry() // Add geometry points to SplineGeometry - netgen::Box<2> box; + netgen::Box<2> box(netgen::Box<2>::EMPTY_BOX); for(auto & s : solids) for(auto & poly : s.polys) for(auto v : poly.Vertices(ALL)) From 334faad05429a7651a2eb192ff47ff4be9005b63 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Thu, 20 Aug 2020 18:25:06 +0200 Subject: [PATCH 120/384] pybind11 - automatic conversion of python list to Array<> --- libsrc/core/python_ngcore.hpp | 50 +++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/libsrc/core/python_ngcore.hpp b/libsrc/core/python_ngcore.hpp index 44ba8033..b26b8481 100644 --- a/libsrc/core/python_ngcore.hpp +++ b/libsrc/core/python_ngcore.hpp @@ -14,6 +14,56 @@ #include "profiler.hpp" namespace py = pybind11; +//////////////////////////////////////////////////////////////////////////////// +// automatic conversion of python list to Array<> +NAMESPACE_BEGIN(PYBIND11_NAMESPACE) +NAMESPACE_BEGIN(detail) + +template struct ngcore_list_caster { + using value_conv = make_caster; + + bool load(handle src, bool convert) { + if (!isinstance(src) || isinstance(src)) + return false; + auto s = reinterpret_borrow(src); + value.SetSize(s.size()); + value.SetSize0(); + for (auto it : s) { + value_conv conv; + if (!conv.load(it, convert)) + return false; + value.Append(cast_op(std::move(conv))); + } + return true; + } + +public: + template + static handle cast(T &&src, return_value_policy policy, handle parent) { + if (!std::is_lvalue_reference::value) + policy = return_value_policy_override::policy(policy); + list l(src.Size()); + size_t index = 0; + for (auto &&value : src) { + auto value_ = reinterpret_steal(value_conv::cast(forward_like(value), policy, parent)); + if (!value_) + return handle(); + PyList_SET_ITEM(l.ptr(), (ssize_t) index++, value_.release().ptr()); // steals a reference + } + return l.release(); + } + + PYBIND11_TYPE_CASTER(Type, _("Array[") + value_conv::name + _("]")); +}; + +template struct type_caster> + : ngcore_list_caster, Type> { }; + + +NAMESPACE_END(detail) +NAMESPACE_END(PYBIND11_NAMESPACE) +//////////////////////////////////////////////////////////////////////////////// + namespace ngcore { NGCORE_API extern bool ngcore_have_numpy; From b9487cc07abbe554084c605db3d8b83bb20acd2e Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Thu, 20 Aug 2020 18:26:25 +0200 Subject: [PATCH 121/384] Rename Polygon2d to Loop --- libsrc/geom2d/csg2d.cpp | 54 ++++++++++++++++----------------- libsrc/geom2d/csg2d.hpp | 12 ++++---- libsrc/geom2d/python_geom2d.cpp | 9 ------ python/geom2d.py | 2 +- 4 files changed, 34 insertions(+), 43 deletions(-) diff --git a/libsrc/geom2d/csg2d.cpp b/libsrc/geom2d/csg2d.cpp index b495d902..5430224b 100644 --- a/libsrc/geom2d/csg2d.cpp +++ b/libsrc/geom2d/csg2d.cpp @@ -628,9 +628,9 @@ void ComputeIntersections(Solid2d & sp, Solid2d & sq) auto & PP = sp.polys; auto & QQ = sq.polys; - for (Polygon2d& P : PP) + for (Loop& P : PP) for (Edge edgeP : P.Edges(SOURCE)) - for (Polygon2d& Q : QQ) + for (Loop& Q : QQ) for (Edge edgeQ : Q.Edges(SOURCE)) { double alpha = 0.0; @@ -688,10 +688,10 @@ void ComputeIntersections(Solid2d & sp, Solid2d & sq) } while(!curr->is_source); }; - for (Polygon2d& P : PP) + for (Loop& P : PP) for (Vertex* v : P.Vertices(SOURCE)) split_spline_at_vertex(v); - for (Polygon2d& Q : QQ) + for (Loop& Q : QQ) for (Vertex* v : Q.Vertices(SOURCE)) split_spline_at_vertex(v); } @@ -770,7 +770,7 @@ void LabelIntersections(Solid2d & sp, Solid2d & sq, Solid2d & sr, bool UNION) auto & RR = sr.polys; // 1) initial classification - for (Polygon2d& P : PP) + for (Loop& P : PP) for (Vertex* I : P.Vertices(INTERSECTION)) { @@ -818,7 +818,7 @@ void LabelIntersections(Solid2d & sp, Solid2d & sq, Solid2d & sr, bool UNION) } // 2) classify intersection chains - for (Polygon2d& P : PP) + for (Loop& P : PP) for (Vertex* I : P.Vertices(INTERSECTION)) { @@ -862,19 +862,19 @@ void LabelIntersections(Solid2d & sp, Solid2d & sq, Solid2d & sr, bool UNION) // 3) copy labels from P to Q // loop over intersection vertices of P - for (Polygon2d& P : PP) + for (Loop& P : PP) for (Vertex* I : P.Vertices(INTERSECTION)) I->neighbour->label = I->label; // 3.5) check for special cases - set noIntersection[2]; - set identical[2]; + set noIntersection[2]; + set identical[2]; for (int i=0; i<2; ++i) { - Array* P_or_Q = &PP; // if i=0, then do it for P w.r.t. Q - Array* Q_or_P = &QQ; + Array* P_or_Q = &PP; // if i=0, then do it for P w.r.t. Q + Array* Q_or_P = &QQ; if (i==1) { // if i=1, then do it for Q w.r.t. P P_or_Q = &QQ; @@ -882,7 +882,7 @@ void LabelIntersections(Solid2d & sp, Solid2d & sq, Solid2d & sr, bool UNION) } // loop over all components of P (or Q) - for (Polygon2d& P : *P_or_Q) + for (Loop& P : *P_or_Q) if (P.noCrossingVertex(UNION)) { // P_ has no crossing vertex (but may have bounces or delayed bounces, except for UNION), @@ -899,7 +899,7 @@ void LabelIntersections(Solid2d & sp, Solid2d & sq, Solid2d & sr, bool UNION) // is P inside Q_or_P? bool isInside = false; auto p = P.getNonIntersectionPoint(); - for (Polygon2d& Q : *Q_or_P) + for (Loop& Q : *Q_or_P) if ( Q.IsInside(p) ) isInside = !isInside; if (isInside ^ UNION) @@ -909,20 +909,20 @@ void LabelIntersections(Solid2d & sp, Solid2d & sq, Solid2d & sr, bool UNION) } // handle components of P that are identical to some component of Q - for (Polygon2d* P : identical[0]) + for (Loop* P : identical[0]) { // is P a hole? bool P_isHole = false; - for (Polygon2d& P_ : PP) + for (Loop& P_ : PP) if ( ( P_.first.get() != P->first.get() ) && (P_.IsInside(*P->first)) ) P_isHole = !P_isHole; - for (Polygon2d* Q : identical[1]) + for (Loop* Q : identical[1]) for (Vertex* V : Q->Vertices(ALL)) if (V == P->first->neighbour) { // found Q that matches P // is Q a hole? bool Q_isHole = false; - for (Polygon2d& Q_ : QQ) + for (Loop& Q_ : QQ) if ( ( Q_.first.get() != Q->first.get() ) && (Q_.IsInside(*Q->first)) ) Q_isHole = !Q_isHole; @@ -940,8 +940,8 @@ next_P: ; for (int i=0; i<2; ++i) { - Array* P_or_Q = &PP; // if i=0, then do it for P w.r.t. Q - Array* Q_or_P = &QQ; + Array* P_or_Q = &PP; // if i=0, then do it for P w.r.t. Q + Array* Q_or_P = &QQ; if (i==1) { // if i=1, then do it for Q w.r.t. P P_or_Q = &QQ; @@ -949,7 +949,7 @@ next_P: ; } // loop over all components of P (or Q) - for (Polygon2d& P : *P_or_Q) + for (Loop& P : *P_or_Q) { // ignore P if it does not intersect with Q_or_P (detected in step 3.5 above) @@ -962,7 +962,7 @@ next_P: ; // check if it is inside or outside Q (or P) // and set ENTRY/EXIT status accordingly EntryExitLabel status = ENTRY; - for (Polygon2d& Q : *Q_or_P) + for (Loop& Q : *Q_or_P) if (Q.IsInside(*V)) ToggleLabel(status); @@ -1122,11 +1122,11 @@ void CreateResult(Solid2d & sp, Solid2d & sr, bool UNION) // so that they cannot serve as start vertex of another component // - for (Polygon2d& P : PP) + for (Loop& P : PP) { for (Vertex* I : P.Vertices(CROSSING_INTERSECTION)) { - Polygon2d R; // result polygon component + Loop R; // result polygon component Vertex* V = I; // start traversal at I V->is_intersection = false; // mark visited vertices @@ -1179,7 +1179,7 @@ void CreateResult(Solid2d & sp, Solid2d & sr, bool UNION) void CleanUpResult(Solid2d & sr) { auto & RR = sr.polys; - for (Polygon2d& R : RR) + for (Loop& R : RR) { while ( (R.first.get() != NULL) && (fabs(Area(*R.first->prev,*R.first,*R.first->next)) < EPSILON) ) R.Remove(R.first.get()); @@ -1211,9 +1211,9 @@ void RemoveDuplicates(Solid2d & sr) } } -Polygon2d RectanglePoly(double x0, double x1, double y0, double y1, string bc) +Loop RectanglePoly(double x0, double x1, double y0, double y1, string bc) { - Polygon2d r; + Loop r; r.Append( {x0, y0} ); r.Append( {x1, y0} ); r.Append( {x1, y1} ); @@ -1235,7 +1235,7 @@ Solid2d Circle(double x, double y, double r, string name, string bc) { Solid2d s; s.name = name; - Polygon2d poly; + Loop poly; Point<2> ps[] = { diff --git a/libsrc/geom2d/csg2d.hpp b/libsrc/geom2d/csg2d.hpp index 210c3d81..abf0b128 100644 --- a/libsrc/geom2d/csg2d.hpp +++ b/libsrc/geom2d/csg2d.hpp @@ -356,20 +356,20 @@ inline int CalcSide( const Point<2> & p0, const Point<2> & p1, const Point<2> & return 0; } -struct Polygon2d +struct Loop { unique_ptr first = nullptr; - Polygon2d() = default; + Loop() = default; - Polygon2d(const Polygon2d & p) + Loop(const Loop & p) : first(nullptr) { for(auto v : p.Vertices(ALL)) AppendVertex(*v); } - Polygon2d & operator=(const Polygon2d & p) + Loop & operator=(const Loop & p) { first = nullptr; if(p.first) @@ -532,7 +532,7 @@ struct Polygon2d struct Solid2d { - Array polys; + Array polys; string name = ""; @@ -543,7 +543,7 @@ struct Solid2d Solid2d operator*(Solid2d & other); Solid2d operator-(Solid2d other); - void Append( const Polygon2d & poly ) + void Append( const Loop & poly ) { polys.Append(poly); } diff --git a/libsrc/geom2d/python_geom2d.cpp b/libsrc/geom2d/python_geom2d.cpp index 1875f6ba..f613fa46 100644 --- a/libsrc/geom2d/python_geom2d.cpp +++ b/libsrc/geom2d/python_geom2d.cpp @@ -408,15 +408,6 @@ DLL_HEADER void ExportGeom2d(py::module &m) .def("SetBC", &Solid2d::SetBC) ; - py::class_(m, "Polygon2d") - .def(py::init<>()) - .def("SetBC", &Polygon2d::SetBC) - .def("Append", [](Polygon2d & self, double x, double y) - { - self.Append({x,y}); - }) - ; - m.def("Rectangle", [](double x0, double x1, double y0, double y1, string bc, string mat) { return Rectangle(x0,x1,y0,y1,bc,mat); }, diff --git a/python/geom2d.py b/python/geom2d.py index 96152cc2..c3336e76 100644 --- a/python/geom2d.py +++ b/python/geom2d.py @@ -1,4 +1,4 @@ -from .libngpy._geom2d import SplineGeometry, Solid2d, Polygon2d, CSG2d, Rectangle, Circle +from .libngpy._geom2d import SplineGeometry, Solid2d, CSG2d, Rectangle, Circle from .meshing import meshsize unit_square = SplineGeometry() From ceb57a7c5c5fe79da578d2ac7e84becaf21aa464 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Thu, 20 Aug 2020 18:27:08 +0200 Subject: [PATCH 122/384] CSG2d interface (Solid2d ctor, EdgeInfo) --- libsrc/geom2d/csg2d.cpp | 28 ++++++++++++++++++++++++++++ libsrc/geom2d/csg2d.hpp | 32 ++++++++++++++++++++++++++++++++ libsrc/geom2d/python_geom2d.cpp | 9 ++++++++- python/geom2d.py | 10 ++++++++-- 4 files changed, 76 insertions(+), 3 deletions(-) diff --git a/libsrc/geom2d/csg2d.cpp b/libsrc/geom2d/csg2d.cpp index 5430224b..ad497ff3 100644 --- a/libsrc/geom2d/csg2d.cpp +++ b/libsrc/geom2d/csg2d.cpp @@ -1322,6 +1322,34 @@ Solid2d ClipSolids ( Solid2d s1, Solid2d s2, bool intersect) return res; } +Solid2d :: Solid2d(const Array, EdgeInfo>> & points, string name_) + : name(name_) +{ + Loop l; + for (auto & v : points) + { + if(std::holds_alternative>(v)) + { + l.Append(std::get<0>(v), true); + } + if(std::holds_alternative(v)) + { + l.first->prev->info.Assign( std::get<1>(v) ); + } + } + + for(auto v : l.Vertices(ALL)) + { + v->bc = v->info.bc; + if(v->info.control_point) + { + v->spline = Spline(*v, *v->info.control_point, *v->next); + } + } + + polys.Append(l); +} + Solid2d Solid2d :: operator+(Solid2d & other) { if(polys.Size()==0) diff --git a/libsrc/geom2d/csg2d.hpp b/libsrc/geom2d/csg2d.hpp index abf0b128..1994bb27 100644 --- a/libsrc/geom2d/csg2d.hpp +++ b/libsrc/geom2d/csg2d.hpp @@ -1,6 +1,8 @@ #ifndef NETGEN_CSG2D_HPP_INCLUDED #define NETGEN_CSG2D_HPP_INCLUDED +#include + #include "geometry2d.hpp" namespace netgen @@ -58,6 +60,34 @@ enum IteratorType ALL }; +inline constexpr const double MAXH_DEFAULT{1e99}; +inline const string BC_DEFAULT{""}; +inline const string MAT_DEFAULT{""}; + +struct EdgeInfo +{ + optional> control_point = nullopt; // for spline segments + double maxh = MAXH_DEFAULT; + string bc = BC_DEFAULT; + + EdgeInfo() = default; + EdgeInfo(Point<2> p) : control_point(p) {} + EdgeInfo(double h) : maxh(h) {} + EdgeInfo(string s) : bc(s) {} + EdgeInfo(optional> p, double h, string s) + : control_point(p), maxh(h), bc(s) + {} + + void Assign( EdgeInfo other ) + { + if(other.control_point != nullopt) + control_point = other.control_point; + if(other.bc != BC_DEFAULT) + bc = other.bc; + if(other.maxh != MAXH_DEFAULT) + maxh = other.maxh; + } +}; using Spline = SplineSeg3<2>; @@ -80,6 +110,7 @@ struct Vertex : Point<2> // In case the edge this - next is curved, store the spline information here optional spline = nullopt; + EdgeInfo info; Vertex * Insert(Point<2> p, double lam = -1.0); @@ -538,6 +569,7 @@ struct Solid2d Solid2d() = default; Solid2d(string name_) : name(name_) {} + Solid2d(const Array, EdgeInfo>> & points, string name_); Solid2d operator+(Solid2d & other); Solid2d operator*(Solid2d & other); diff --git a/libsrc/geom2d/python_geom2d.cpp b/libsrc/geom2d/python_geom2d.cpp index f613fa46..fb550d79 100644 --- a/libsrc/geom2d/python_geom2d.cpp +++ b/libsrc/geom2d/python_geom2d.cpp @@ -399,7 +399,7 @@ DLL_HEADER void ExportGeom2d(py::module &m) py::class_(m, "Solid2d") .def(py::init<>()) - .def(py::init()) + .def(py::init, EdgeInfo>>, std::string>(), py::arg("points"), py::arg("mat")=MAT_DEFAULT) .def_readwrite("name", &Solid2d::name) .def("__mul__", [](Solid2d & self, Solid2d & other) { return self*other; }) .def("__add__", [](Solid2d & self, Solid2d & other) { return self+other; }) @@ -421,6 +421,13 @@ DLL_HEADER void ExportGeom2d(py::module &m) .def("Add", &CSG2d::Add) ; + py::class_(m, "EdgeInfo") + .def(py::init<>()) + .def(py::init&>(), py::arg("control_point")) + .def(py::init(), py::arg("maxh")) + .def(py::init(), py::arg("bc")) + .def(py::init>, double, string>(), py::arg("control_point")=nullopt, py::arg("maxh")=MAXH_DEFAULT, py::arg("bc")=BC_DEFAULT) + ; } PYBIND11_MODULE(libgeom2d, m) { diff --git a/python/geom2d.py b/python/geom2d.py index c3336e76..c4cdf3c7 100644 --- a/python/geom2d.py +++ b/python/geom2d.py @@ -1,4 +1,4 @@ -from .libngpy._geom2d import SplineGeometry, Solid2d, CSG2d, Rectangle, Circle +from .libngpy._geom2d import SplineGeometry, Solid2d, CSG2d, Rectangle, Circle, EdgeInfo from .meshing import meshsize unit_square = SplineGeometry() @@ -137,4 +137,10 @@ SplineGeometry.AddSegment = lambda *args, **kwargs : SplineGeometry.Append(*args SplineGeometry.AddPoint = lambda *args, **kwargs : SplineGeometry.AppendPoint(*args, **kwargs) SplineGeometry.CreatePML = CreatePML - +bc = lambda s : EdgeInfo(bc=s) +maxh = lambda h : EdgeInfo(maxh=h) +def cp(p_or_px, py_or_none = None): + if py_or_none is None: + return EdgeInfo(control_point=p) + else: + return EdgeInfo(control_point=(p_or_px,py_or_none)) From e2768981f1c5eb28567e8e83e8eb1b97779a1f72 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Thu, 20 Aug 2020 18:28:03 +0200 Subject: [PATCH 123/384] implicit conversion from py::tuple to Point<2> --- libsrc/meshing/python_mesh.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libsrc/meshing/python_mesh.cpp b/libsrc/meshing/python_mesh.cpp index 3641ca15..64e3e0c8 100644 --- a/libsrc/meshing/python_mesh.cpp +++ b/libsrc/meshing/python_mesh.cpp @@ -163,6 +163,10 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m) py::class_> (m, "Point2d") .def(py::init()) + .def(py::init( [] (std::pair xy) + { + return Point<2>{xy.first, xy.second}; + })) .def ("__str__", &ToString>) .def(py::self-py::self) .def(py::self+Vec<2>()) @@ -170,6 +174,8 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m) .def("__getitem__", [](Point<2>& self, int index) { return self[index]; }) ; + py::implicitly_convertible>(); + py::class_> (m, "Point3d") .def(py::init()) .def ("__str__", &ToString>) From c4f214651901fc7369a33774672b417cdea213ea Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Fri, 21 Aug 2020 11:51:28 +0200 Subject: [PATCH 124/384] use get_if for variant<> compiles for Mac <10.13, also more readable --- libsrc/geom2d/csg2d.cpp | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/libsrc/geom2d/csg2d.cpp b/libsrc/geom2d/csg2d.cpp index ad497ff3..1f323193 100644 --- a/libsrc/geom2d/csg2d.cpp +++ b/libsrc/geom2d/csg2d.cpp @@ -1328,14 +1328,10 @@ Solid2d :: Solid2d(const Array, EdgeInfo>> & points, strin Loop l; for (auto & v : points) { - if(std::holds_alternative>(v)) - { - l.Append(std::get<0>(v), true); - } - if(std::holds_alternative(v)) - { - l.first->prev->info.Assign( std::get<1>(v) ); - } + if(auto point = std::get_if>(&v)) + l.Append(*point, true); + if(auto edge_info = std::get_if(&v)) + l.first->prev->info.Assign( *edge_info ); } for(auto v : l.Vertices(ALL)) From 895280a2443bd0d75595e96451014fcd85f13b10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20Sch=C3=B6berl?= Date: Fri, 21 Aug 2020 16:29:33 +0200 Subject: [PATCH 125/384] littel parallel polishing --- libsrc/include/nginterface_v2.hpp | 5 +- libsrc/interface/nginterface.cpp | 3 + libsrc/interface/nginterface_v2.cpp | 27 +++---- libsrc/meshing/meshclass.cpp | 83 --------------------- libsrc/meshing/parallelmesh.cpp | 7 +- libsrc/meshing/paralleltop.cpp | 112 +++++++++++++++++++++++++++- libsrc/meshing/paralleltop.hpp | 38 +++++++--- 7 files changed, 161 insertions(+), 114 deletions(-) diff --git a/libsrc/include/nginterface_v2.hpp b/libsrc/include/nginterface_v2.hpp index 653f7ead..fc1b860f 100644 --- a/libsrc/include/nginterface_v2.hpp +++ b/libsrc/include/nginterface_v2.hpp @@ -368,8 +368,9 @@ namespace netgen // for MPI-parallel - std::tuple GetDistantProcs (int nodetype, int locnum) const; - + FlatArray GetDistantProcs (int nodetype, int locnum) const; + size_t GetGlobalVertexNum (int locnum) const; + shared_ptr GetMesh () const { return mesh; } shared_ptr SelectMesh () const; inline auto GetTimeStamp() const; diff --git a/libsrc/interface/nginterface.cpp b/libsrc/interface/nginterface.cpp index 42d26094..c6bdd3fc 100644 --- a/libsrc/interface/nginterface.cpp +++ b/libsrc/interface/nginterface.cpp @@ -905,6 +905,7 @@ void Ng_GetSurfaceElementNeighbouringDomains(const int selnr, int & in, int & ou // gibt anzahl an distant pnums zurueck // * pnums entspricht ARRAY +[[deprecated("Use GetDistantNodeNums(locnum) -> FlatArray instead!")]] int NgPar_GetDistantNodeNums ( int nodetype, int locnum, int * distnums ) { int size = NgPar_GetNDistantNodeNums (nodetype, locnum); @@ -931,6 +932,7 @@ int NgPar_GetDistantNodeNums ( int nodetype, int locnum, int * distnums ) return size; } +[[deprecated("Use GetDistantNodeNums(locnum) -> FlatArray instead!")]] int NgPar_GetNDistantNodeNums ( int nodetype, int locnum ) { locnum++; @@ -944,6 +946,7 @@ int NgPar_GetNDistantNodeNums ( int nodetype, int locnum ) return -1; } +[[deprecated("Use GetDistantNodeNums(locnum) -> FlatArray instead!")]] int NgPar_GetGlobalNodeNum (int nodetype, int locnum) { locnum++; diff --git a/libsrc/interface/nginterface_v2.cpp b/libsrc/interface/nginterface_v2.cpp index e2501ab4..b82868ee 100644 --- a/libsrc/interface/nginterface_v2.cpp +++ b/libsrc/interface/nginterface_v2.cpp @@ -1296,36 +1296,31 @@ void Ngx_Mesh::SetSurfaceElementOrders (int enr, int ox, int oy) +size_t Ngx_Mesh :: GetGlobalVertexNum (int locnum) const +{ + return mesh->GetParallelTopology().GetGlobalPNum (locnum+1)-1; +} - std::tuple Ngx_Mesh :: GetDistantProcs (int nodetype, int locnum) const +FlatArray Ngx_Mesh :: GetDistantProcs (int nodetype, int locnum) const { #ifdef PARALLEL if (mesh->GetCommunicator().Size() == 1) - return std::tuple(0,nullptr); + return FlatArray(0,nullptr); switch (nodetype) { case 0: - { - NgFlatArray dn = mesh->GetParallelTopology().GetDistantPNums(locnum); - return std::tuple(dn.Size(), &dn[0]); - } + return mesh->GetParallelTopology().GetDistantPNums(locnum); case 1: - { - NgFlatArray dn = mesh->GetParallelTopology().GetDistantEdgeNums(locnum); - return std::tuple(dn.Size(), &dn[0]); - } + return mesh->GetParallelTopology().GetDistantEdgeNums(locnum); case 2: - { - NgFlatArray dn = mesh->GetParallelTopology().GetDistantFaceNums(locnum); - return std::tuple(dn.Size(), &dn[0]); - } + return mesh->GetParallelTopology().GetDistantFaceNums(locnum); default: - return std::tuple(0,nullptr); + return FlatArray(0, nullptr); } #else - return std::tuple(0,nullptr); + return FlatArray(0,nullptr); #endif } } diff --git a/libsrc/meshing/meshclass.cpp b/libsrc/meshing/meshclass.cpp index 5b859931..7006ea07 100644 --- a/libsrc/meshing/meshclass.cpp +++ b/libsrc/meshing/meshclass.cpp @@ -1298,89 +1298,6 @@ namespace netgen // GridFunciton pickling is not compatible, now // should go to paralleltopology - Array global_pnums(points.Size()); - global_pnums = -1; - int num_master_points = 0; - for (PointIndex pi : Range(points)) - { - auto distprocs = partop.GetDistantPNums(pi-PointIndex::BASE); - // check sorted: - for (int j = 0; j+1 < distprocs.Size(); j++) - if (distprocs[j+1] < distprocs[j]) cout << "wrong sort" << endl; - if (distprocs.Size() == 0 || distprocs[0] > comm.Rank()) - global_pnums[pi] = PointIndex::BASE+num_master_points++; - } - Array first_master_point(comm.Size()); - GetCommunicator().AllGather (num_master_points, first_master_point); - - size_t num_glob_points = 0; - for (int i = 0; i < comm.Size(); i++) - { - int cur = first_master_point[i]; - first_master_point[i] = num_glob_points; - num_glob_points += cur; - } - - for (PointIndex pi : Range(points)) - if (global_pnums[pi] != -1) - global_pnums[pi] += first_master_point[comm.Rank()]; - - // ScatterDofData (global_nums); - - Array nsend(comm.Size()), nrecv(comm.Size()); - nsend = 0; - nrecv = 0; - - /** Count send/recv size **/ - for (PointIndex pi : Range(points)) - { - auto dps = partop.GetDistantPNums(pi-PointIndex::BASE); - if (!dps.Size()) continue; - if (rank < dps[0]) - for(auto p:dps) - nsend[p]++; - else - nrecv[dps[0]]++; - } - - Table send_data(nsend); - Table recv_data(nrecv); - - /** Fill send_data **/ - nsend = 0; - for (PointIndex pi : Range(points)) - { - auto dps = partop.GetDistantPNums(pi-PointIndex::BASE); - if (dps.Size() && rank < dps[0]) - for(auto p : dps) - send_data[p][nsend[p]++] = global_pnums[pi]; - } - - Array requests; - for (int i = 0; i < comm.Size(); i++) - { - if (nsend[i]) - requests.Append (comm.ISend (send_data[i], i, 200)); - if (nrecv[i]) - requests.Append (comm.IRecv (recv_data[i], i, 200)); - } - - MyMPI_WaitAll (requests); - - Array cnt(comm.Size()); - cnt = 0; - - for (PointIndex pi : Range(points)) - { - auto distprocs = partop.GetDistantPNums(pi-PointIndex::BASE); - if (distprocs.Size() > 0 && distprocs[0] < comm.Rank()) - { - int master = comm.Size(); - for (int j = 0; j < distprocs.Size(); j++) - master = min (master, distprocs[j]); - global_pnums[pi] = recv_data[master][cnt[master]++]; - } - } // merge points diff --git a/libsrc/meshing/parallelmesh.cpp b/libsrc/meshing/parallelmesh.cpp index a7c13d23..b17490ae 100644 --- a/libsrc/meshing/parallelmesh.cpp +++ b/libsrc/meshing/parallelmesh.cpp @@ -732,6 +732,7 @@ namespace netgen for (auto t : point_types) { MPI_Type_free(&t); } + PrintMessage ( 3, "Sending names"); sendrequests.SetSize(3*ntasks); @@ -814,6 +815,9 @@ namespace netgen self.BuildElementSearchTree(); // const_cast(*this).DeleteMesh(); + + // paralleltop -> SetNV (0); + // paralleltop->EnumeratePointsGlobally(); PrintMessage( 3, "send mesh complete"); } @@ -1016,6 +1020,7 @@ namespace netgen } } + /** Recv bc-names **/ ArrayMem nnames{0,0,0,0}; // MPI_Recv(nnames, 4, MPI_INT, 0, MPI_TAG_MESH+6, comm, MPI_STATUS_IGNORE); @@ -1073,7 +1078,7 @@ namespace netgen clusters -> Update(); // paralleltop -> UpdateCoarseGrid(); - + // paralleltop->EnumeratePointsGlobally(); SetNextMajorTimeStamp(); } diff --git a/libsrc/meshing/paralleltop.cpp b/libsrc/meshing/paralleltop.cpp index 9e07fd73..91c5f9ad 100644 --- a/libsrc/meshing/paralleltop.cpp +++ b/libsrc/meshing/paralleltop.cpp @@ -55,6 +55,107 @@ namespace netgen } + void ParallelMeshTopology :: EnumeratePointsGlobally () + { + auto nv = loc2distvert.Size(); + auto comm = mesh.GetCommunicator(); + auto rank = comm.Rank(); + + // if (rank == 0) + // nv = 0; + glob_vert.SetSize (nv); + glob_vert = -1; + int num_master_points = 0; + + for (auto i : Range(nv)) + { + auto dps = GetDistantPNums(i); + // check sorted: + for (int j = 0; j+1 < dps.Size(); j++) + if (dps[j+1] < dps[j]) cout << "wrong sort" << endl; + + if (dps.Size() == 0 || dps[0] > comm.Rank()) + glob_vert[i] = num_master_points++; + } + + Array first_master_point(comm.Size()); + comm.AllGather (num_master_points, first_master_point); + + size_t num_glob_points = 0; + for (int i = 0; i < comm.Size(); i++) + { + int cur = first_master_point[i]; + first_master_point[i] = num_glob_points; + num_glob_points += cur; + } + + for (auto i : Range(nv)) + if (glob_vert[i] != -1) + glob_vert[i] += first_master_point[comm.Rank()]; + + // ScatterDofData (global_nums); + + Array nsend(comm.Size()), nrecv(comm.Size()); + nsend = 0; + nrecv = 0; + + /** Count send/recv size **/ + for (auto i : Range(nv)) + { + auto dps = GetDistantPNums(i); + if (!dps.Size()) continue; + if (rank < dps[0]) + for(auto p:dps) + nsend[p]++; + else + nrecv[dps[0]]++; + } + + Table send_data(nsend); + Table recv_data(nrecv); + + /** Fill send_data **/ + nsend = 0; + for (auto i : Range(nv)) + { + auto dps = GetDistantPNums(i); + if (dps.Size() && rank < dps[0]) + for(auto p : dps) + send_data[p][nsend[p]++] = glob_vert[i]; + } + + Array requests; + for (int i = 0; i < comm.Size(); i++) + { + if (nsend[i]) + requests.Append (comm.ISend (send_data[i], i, 200)); + if (nrecv[i]) + requests.Append (comm.IRecv (recv_data[i], i, 200)); + } + + MyMPI_WaitAll (requests); + + Array cnt(comm.Size()); + cnt = 0; + + for (auto i : Range(nv)) + { + auto dps = GetDistantPNums(i); + if (dps.Size() > 0 && dps[0] < comm.Rank()) + { + int master = comm.Size(); + for (int j = 0; j < dps.Size(); j++) + master = min (master, dps[j]); + glob_vert[i] = recv_data[master][cnt[master]++]; + } + } + + if (PointIndex::BASE==1) + for (auto & i : glob_vert) + i++; + } + + void ParallelMeshTopology :: SetDistantFaceNum (int dest, int locnum) { for ( int i = 0; i < loc2distface[locnum-1].Size(); i+=1 ) @@ -242,8 +343,13 @@ namespace netgen MPI_Group_excl (MPI_GROUP_comm, 1, process_ranks, &MPI_LocalGroup); MPI_Comm_create (comm, MPI_LocalGroup, &MPI_LocalComm); - if (id == 0) return; - + if (id == 0) + { + // SetNV(0); + // EnumeratePointsGlobally(); + return; + } + const MeshTopology & topology = mesh.GetTopology(); NgArray cnt_send(ntasks-1); @@ -573,7 +679,7 @@ namespace netgen NgProfiler::StopTimer (timerf); } // cout << "UpdateCoarseGrid - done" << endl; - + // EnumeratePointsGlobally(); is_updated = true; MPI_Group_free(&MPI_LocalGroup); diff --git a/libsrc/meshing/paralleltop.hpp b/libsrc/meshing/paralleltop.hpp index 197ba62e..6f223928 100644 --- a/libsrc/meshing/paralleltop.hpp +++ b/libsrc/meshing/paralleltop.hpp @@ -42,60 +42,80 @@ namespace netgen void SetNSE (int anse); void SetNSegm (int anseg); - void SetLoc2Glob_Vert (int locnum, int globnum) { glob_vert[locnum-1] = globnum; } + [[deprecated("Try to avoid global enumration!")]] void SetLoc2Glob_Edge (int locnum, int globnum) { glob_edge[locnum-1] = globnum; } + [[deprecated("Try to avoid global enumration!")]] void SetLoc2Glob_Face (int locnum, int globnum) { glob_face[locnum-1] = globnum; } + [[deprecated("Try to avoid global enumration!")]] void SetLoc2Glob_VolEl (int locnum, int globnum) { glob_el[locnum-1] = globnum; } + [[deprecated("Try to avoid global enumration!")]] void SetLoc2Glob_SurfEl (int locnum, int globnum) { glob_surfel[locnum-1] = globnum; } + [[deprecated("Try to avoid global enumration!")]] void SetLoc2Glob_Segm (int locnum, int globnum) { glob_segm[locnum-1] = globnum; } int GetGlobalPNum (int locnum) const { return glob_vert[locnum-1]; } + [[deprecated("Try to avoid global enumration!")]] int GetGlobalEdgeNum (int locnum) const { return glob_edge[locnum-1]; } + [[deprecated("Try to avoid global enumration!")]] int GetGlobalFaceNum (int locnum) const { return glob_face[locnum-1]; } + [[deprecated("Try to avoid global enumration!")]] int GetGlobalElNum (int locnum) const { return glob_el[locnum-1]; } + [[deprecated("Try to avoid global enumration!")]] int GetGlobalSElNum (int locnum) const { return glob_surfel[locnum-1]; } + void EnumeratePointsGlobally (); + void SetDistantFaceNum (int dest, int locnum); void SetDistantPNum (int dest, int locnum); void SetDistantEdgeNum (int dest, int locnum); - int GetNDistantPNums (int locpnum) const { return loc2distvert[locpnum-1].Size(); } - int GetNDistantFaceNums (int locfacenum) const { return loc2distface[locfacenum-1].Size(); } + [[deprecated("Use GetDistantPNums(locnum).Size() instead!")]] + int GetNDistantPNums (int locpnum) const { return loc2distvert[locpnum-1].Size(); } + + [[deprecated("Use GetDistantFaceNums(locnum).Size() instead!")]] + int GetNDistantFaceNums (int locfacenum) const { return loc2distface[locfacenum-1].Size(); } + + [[deprecated("Use GetDistantEdgeNums(locnum).Size() instead!")]] int GetNDistantEdgeNums ( int locedgenum) const { return loc2distedge[locedgenum-1].Size(); } - + + [[deprecated("Use GetDistantPNums(locnum) -> FlatArray instead!")]] void GetDistantPNums (int locpnum, int * distpnums ) const { for (int i = 0; i < loc2distvert[locpnum-1].Size(); i++ ) distpnums[i] = loc2distvert[locpnum-1][i]; } - + + [[deprecated("Use GetDistantFaceNums(locnum) -> FlatArray instead!")]] void GetDistantFaceNums (int locfacenum, int * distfacenums ) const { for ( int i = 0; i < loc2distface[locfacenum-1].Size(); i++ ) distfacenums[i] = loc2distface[locfacenum-1][i]; } + [[deprecated("Use GetDistantFaceNums(locnum) -> FlatArray instead!")]] void GetDistantFaceNums (int locfacenum, NgArray & distfacenums ) const { distfacenums = loc2distface[locfacenum-1]; } - + + [[deprecated("Use GetDistantEdgeNums(locnum) -> FlatArray instead!")]] void GetDistantEdgeNums (int locedgenum, int * distedgenums ) const { for (int i = 0; i < loc2distedge[locedgenum-1].Size(); i++ ) distedgenums[i] = loc2distedge[locedgenum-1][i]; } + [[deprecated("Use GetDistantEdgeNums(locnum) -> FlatArray instead!")]] void GetDistantEdgeNums (int locedgenum, NgArray & distedgenums ) const { distedgenums = loc2distedge[locedgenum-1]; } - NgFlatArray GetDistantPNums (int locnum) const { return loc2distvert[locnum]; } - NgFlatArray GetDistantFaceNums (int locnum) const { return loc2distface[locnum]; } - NgFlatArray GetDistantEdgeNums (int locnum) const { return loc2distedge[locnum]; } + FlatArray GetDistantPNums (int locnum) const { return loc2distvert[locnum]; } + FlatArray GetDistantFaceNums (int locnum) const { return loc2distface[locnum]; } + FlatArray GetDistantEdgeNums (int locnum) const { return loc2distedge[locnum]; } bool IsExchangeVert (int dest, int vnum) const { From e680f23bfa06267c4b3862d077acbf148943796f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20Sch=C3=B6berl?= Date: Fri, 21 Aug 2020 22:38:35 +0200 Subject: [PATCH 126/384] fix for non-parallel --- libsrc/interface/nginterface_v2.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libsrc/interface/nginterface_v2.cpp b/libsrc/interface/nginterface_v2.cpp index b82868ee..a276f376 100644 --- a/libsrc/interface/nginterface_v2.cpp +++ b/libsrc/interface/nginterface_v2.cpp @@ -1298,7 +1298,11 @@ void Ngx_Mesh::SetSurfaceElementOrders (int enr, int ox, int oy) size_t Ngx_Mesh :: GetGlobalVertexNum (int locnum) const { +#ifdef PARALLEL return mesh->GetParallelTopology().GetGlobalPNum (locnum+1)-1; +#else + return locnum; +#endif } From 58631362857d9127d958c62e050ad9110a5986b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20Sch=C3=B6berl?= Date: Sun, 23 Aug 2020 18:47:49 +0200 Subject: [PATCH 127/384] MaybeTrue/False for xbool --- libsrc/core/xbool.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libsrc/core/xbool.hpp b/libsrc/core/xbool.hpp index 8feb3fef..2063ebf7 100644 --- a/libsrc/core/xbool.hpp +++ b/libsrc/core/xbool.hpp @@ -30,6 +30,8 @@ namespace ngcore bool IsTrue () const { return state == 2; } bool IsMaybe () const { return state == 1; } bool IsFalse () const { return state == 0; } + bool IsMaybeTrue() const { return state >= 1; } + bool IsMaybeFalse() const { return state <= 1; } friend ostream & operator<< (ostream & ost, xbool xb); }; From 671566ef31414c44c0aafd174dd401de3a2b20ed Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Mon, 24 Aug 2020 11:34:54 +0200 Subject: [PATCH 128/384] csg2d interface --- libsrc/geom2d/csg2d.cpp | 155 ++++++++++++++++++++++---------- libsrc/geom2d/csg2d.hpp | 59 ++++++++---- libsrc/geom2d/python_geom2d.cpp | 23 +++-- 3 files changed, 169 insertions(+), 68 deletions(-) diff --git a/libsrc/geom2d/csg2d.cpp b/libsrc/geom2d/csg2d.cpp index 1f323193..9a1a208c 100644 --- a/libsrc/geom2d/csg2d.cpp +++ b/libsrc/geom2d/csg2d.cpp @@ -15,6 +15,22 @@ namespace netgen constexpr static double EPSILON=0.000000001; +void ComputeWeight( Spline & s, Point<2> p ) +{ + Point<2> a = s.StartPI(); + Point<2> b = s.TangentPoint(); + Point<2> c = s.EndPI(); + + double A = (p[1]-a[1])*(b[0]-p[0]) - (p[0]-a[0])*(b[1]-p[1]); + double B = (p[1]-c[1])*(b[0]-p[0]) - (p[0]-c[0])*(b[1]-p[1]); + double det = sqrt(-A*B); + double tt = (B-det)/(A+det); + auto v = b-p; + int dim = fabs(v[0]) > fabs(v[1]) ? 0 : 1; + double weight = fabs(tt*(p[dim]-a[dim])/v[dim] + 1.0/tt*(p[dim]-c[dim])/v[dim]); + s.SetWeight(weight); +} + void ToggleLabel(EntryExitLabel& status) { if (status == ENTRY) @@ -61,14 +77,7 @@ Spline Split( const Spline & s, double t0, double t1 ) // compute weight of new spline such that p lies on it Point<2> p = s.GetPoint(0.5*(t0+t1)); - double A = (p[1]-a[1])*(b[0]-p[0]) - (p[0]-a[0])*(b[1]-p[1]); - double B = (p[1]-c[1])*(b[0]-p[0]) - (p[0]-c[0])*(b[1]-p[1]); - double det = sqrt(-A*B); - double tt = (B-det)/(A+det); - auto v = b-p; - int dim = fabs(v[0]) > fabs(v[1]) ? 0 : 1; - double weight = fabs(tt*(p[dim]-a[dim])/v[dim] + 1.0/tt*(p[dim]-c[dim])/v[dim]); - res.SetWeight(weight); + ComputeWeight(res, p); return res; } @@ -1222,45 +1231,35 @@ Loop RectanglePoly(double x0, double x1, double y0, double y1, string bc) return r; } -Solid2d Rectangle(double x0, double x1, double y0, double y1, string name, string bc) +Solid2d Rectangle(Point<2> p0, Point<2> p1, string name, string bc) { - Solid2d s; - s.name = name; - s.polys.Append(RectanglePoly(x0,x1,y0,y1, bc)); - s.SetBC(bc); - return s; + using P = Point<2>; + return { {p0, P{p1[0],p0[1]}, p1, P{p0[0],p1[1]}}, name, bc }; } -Solid2d Circle(double x, double y, double r, string name, string bc) +Solid2d Circle(Point<2> center, double r, string name, string bc) { - Solid2d s; - s.name = name; - Loop poly; + double x = center[0]; + double y = center[1]; + using P = Point<2>; - Point<2> ps[] = + Point<2> p[] = { {x+r, y+0}, - {x+r, y+r}, {x+0, y+r}, - {x-r, y+r}, {x-r, y+0}, - {x-r, y-r}, {x+0, y-r}, - {x+r, y-r} }; - for (auto i : IntRange(4)) + EdgeInfo cp[] = { - int i0 = 2*i; - int i1 = (i0+1)%8; - int i2 = (i0+2)%8; - auto & v0 = poly.Append( ps[i0] ); - v0.spline = { ps[i0], ps[i1], ps[i2] }; - } + P{x+r, y+r}, + P{x-r, y+r}, + P{x-r, y-r}, + P{x+r, y-r} + }; - s.polys.Append(poly); - s.SetBC(bc); - return s; + return Solid2d( { p[0], cp[0], p[1], cp[1], p[2], cp[2], p[3], cp[3] }, name, bc ); } Solid2d AddIntersectionPoints ( Solid2d s1, Solid2d s2 ) @@ -1322,7 +1321,7 @@ Solid2d ClipSolids ( Solid2d s1, Solid2d s2, bool intersect) return res; } -Solid2d :: Solid2d(const Array, EdgeInfo>> & points, string name_) +Solid2d :: Solid2d(const Array, EdgeInfo>> & points, string name_, string bc) : name(name_) { Loop l; @@ -1336,6 +1335,9 @@ Solid2d :: Solid2d(const Array, EdgeInfo>> & points, strin for(auto v : l.Vertices(ALL)) { + if(v->info.bc==BC_DEFAULT) + v->info.bc = bc; + v->bc = v->info.bc; if(v->info.control_point) { @@ -1346,7 +1348,7 @@ Solid2d :: Solid2d(const Array, EdgeInfo>> & points, strin polys.Append(l); } -Solid2d Solid2d :: operator+(Solid2d & other) +Solid2d Solid2d :: operator+(const Solid2d & other) const { if(polys.Size()==0) return other; @@ -1356,16 +1358,17 @@ Solid2d Solid2d :: operator+(Solid2d & other) return res; } -Solid2d Solid2d :: operator*(Solid2d & other) +Solid2d Solid2d :: operator*(const Solid2d & other) const { auto res = ClipSolids(*this, other, true); res.name = name; return res; } -Solid2d Solid2d :: operator-(Solid2d other) +Solid2d Solid2d :: operator-(const Solid2d & other_) const { // TODO: Check dimensions of solids with bounding box + Solid2d other = other_; other.Append(RectanglePoly(-1e8, 1e8, -1e8, 1e8, "JUST_FOR_CLIPPING")); auto res = ClipSolids(*this, other); @@ -1379,6 +1382,54 @@ Solid2d Solid2d :: operator-(Solid2d other) return res; } +Solid2d Solid2d :: operator+=(const Solid2d & other) +{ + *this = *this + other; + return *this; +} + +Solid2d Solid2d :: operator*=(const Solid2d & other) +{ + *this = *this * other; + return *this; +} + +Solid2d Solid2d :: operator-=(const Solid2d & other) +{ + *this = *this - other; + return *this; +} + +Solid2d & Solid2d :: Move( Vec<2> v ) +{ + return Transform( [v](Point<2> p) -> Point<2> { return p+v; } ); +} + +Solid2d & Solid2d :: Scale( double sx, double sy ) +{ + if(sy==0.0) + sy=sx; + return Transform( [sx,sy](Point<2> p) -> Point<2> { return{p[0]*sx, p[1]*sy}; } ); +} + +Solid2d & Solid2d :: RotateRad( double ang, Point<2> center ) +{ + double sina = sin(ang); + double cosa = cos(ang); + Vec<2> c = { center[0], center[1] }; + return Transform( [c, sina, cosa](Point<2> p) -> Point<2> + { + p -= c; + double x = p[0]; + double y = p[1]; + p[0] = cosa*x+sina*y; + p[1] = -sina*x+cosa*y; + p += c; + return p; + } ); +} + + bool Solid2d :: IsInside( Point<2> r ) const { int w = 0; @@ -1406,7 +1457,6 @@ bool Solid2d :: IsRightInside( const Vertex & p0 ) return IsInside(q); } - shared_ptr CSG2d :: GenerateSplineGeometry() { static Timer t_intersections("CSG2d - AddIntersections()"); @@ -1519,20 +1569,24 @@ shared_ptr CSG2d :: GenerateSplineGeometry() auto li = s.IsLeftInside(p0); auto ri = s.IsRightInside(p0); + auto & ls = seg_map[{pi0,pi1,pi2}]; + ls.p0 = pi0; + ls.p1 = pi1; + ls.p2 = pi2; + ls.weight = weight; + + if(bcmap.count(p0.bc)==0) + bcmap[p0.bc] = bcmap.size()+1; + + if(ls.bc==0 || p0.bc != BC_DEFAULT) + ls.bc = bcmap[p0.bc]; + if(li!=ri) { - auto & ls = seg_map[{pi0,pi1,pi2}]; - ls.p0 = pi0; - ls.p1 = pi1; - ls.p2 = pi2; - ls.weight = weight; if(s.IsLeftInside(p0) == flip) ls.left = dom; else ls.right = dom; - if(bcmap.count(p0.bc)==0) - bcmap[p0.bc] = bcmap.size()+1; - ls.bc = bcmap[p0.bc]; } } } @@ -1570,4 +1624,13 @@ shared_ptr CSG2d :: GenerateSplineGeometry() } return geo; } + +shared_ptr CSG2d :: GenerateMesh(MeshingParameters & mp) +{ + auto geo = GenerateSplineGeometry(); + auto mesh = make_shared(); + geo->GenerateMesh(mesh, mp); + return mesh; +} + } diff --git a/libsrc/geom2d/csg2d.hpp b/libsrc/geom2d/csg2d.hpp index 1994bb27..c56859f8 100644 --- a/libsrc/geom2d/csg2d.hpp +++ b/libsrc/geom2d/csg2d.hpp @@ -11,12 +11,15 @@ namespace netgen using namespace ngcore; using netgen::Point; using netgen::Vec; +using Spline = SplineSeg3<2>; inline double Area(const Point<2>& P, const Point<2>& Q, const Point<2>& R) { return (Q[0]-P[0]) * (R[1]-P[1]) - (Q[1]-P[1]) * (R[0]-P[0]); } +// compute weight of spline such that p lies on it +void ComputeWeight( Spline & s, Point<2> p ); enum IntersectionType { // types of intersection (detected in the first phase) @@ -89,8 +92,6 @@ struct EdgeInfo } }; -using Spline = SplineSeg3<2>; - struct Vertex : Point<2> { Vertex (Point<2> p) : Point<2>(p) {} @@ -565,15 +566,20 @@ struct Solid2d { Array polys; - string name = ""; + string name = MAT_DEFAULT; Solid2d() = default; Solid2d(string name_) : name(name_) {} - Solid2d(const Array, EdgeInfo>> & points, string name_); + Solid2d(const Array, EdgeInfo>> & points, string name_=MAT_DEFAULT, string bc_=BC_DEFAULT); - Solid2d operator+(Solid2d & other); - Solid2d operator*(Solid2d & other); - Solid2d operator-(Solid2d other); + Solid2d operator+(const Solid2d & other) const; + Solid2d operator*(const Solid2d & other) const; + Solid2d operator-(const Solid2d & other) const; + + Solid2d& operator=(const Solid2d & other) = default; + Solid2d operator+=(const Solid2d & other); + Solid2d operator*=(const Solid2d & other); + Solid2d operator-=(const Solid2d & other); void Append( const Loop & poly ) { @@ -584,14 +590,36 @@ struct Solid2d bool IsLeftInside( const Vertex & p0 ); bool IsRightInside( const Vertex & p0 ); - void SetBC(string bc) - { - for(auto & p : polys) - for(auto v : p.Vertices(ALL)) - v->bc = bc; - } + template + Solid2d & Transform( const TFunc & func ) + { + for(auto & poly : polys) + for(auto v : poly.Vertices(ALL)) + { + auto p = func(*v); + (*v)[0] = p[0]; + (*v)[1] = p[1]; + if(v->spline) + { + auto &s = *v->spline; + auto pmid = func(s.GetPoint(0.5)); + s = Spline(func(s.StartPI()), func(s.TangentPoint()), func(s.EndPI())); + ComputeWeight(s, pmid); + } + } + return *this; + } + + Solid2d & Move( Vec<2> v ); + Solid2d & Scale( double sx, double sy=0.0 ); + Solid2d & RotateRad( double ang, Point<2> center = {0,0} ); + Solid2d & RotateDeg( double ang, Point<2> center = {0,0} ) + { + return RotateRad( ang/180.*M_PI ); + } }; + class CSG2d { public: @@ -603,10 +631,11 @@ class CSG2d } shared_ptr GenerateSplineGeometry(); + shared_ptr GenerateMesh(MeshingParameters & mp); }; -Solid2d Circle(double x, double y, double r, string name="", string bc=""); -Solid2d Rectangle(double x0, double x1, double y0, double y1, string name, string bc); +Solid2d Circle( Point<2> center, double r, string name="", string bc=""); +Solid2d Rectangle( Point<2> p0, Point<2> p1, string mat=MAT_DEFAULT, string bc=BC_DEFAULT ); Solid2d AddIntersectionPoints ( Solid2d s1, Solid2d s2 ); Solid2d ClipSolids ( Solid2d s1, Solid2d s2, bool intersect=true ); diff --git a/libsrc/geom2d/python_geom2d.cpp b/libsrc/geom2d/python_geom2d.cpp index fb550d79..59de6c51 100644 --- a/libsrc/geom2d/python_geom2d.cpp +++ b/libsrc/geom2d/python_geom2d.cpp @@ -399,21 +399,30 @@ DLL_HEADER void ExportGeom2d(py::module &m) py::class_(m, "Solid2d") .def(py::init<>()) - .def(py::init, EdgeInfo>>, std::string>(), py::arg("points"), py::arg("mat")=MAT_DEFAULT) + .def(py::init, EdgeInfo>>, std::string, std::string>(), py::arg("points"), py::arg("mat")=MAT_DEFAULT, py::arg("bc")=BC_DEFAULT) .def_readwrite("name", &Solid2d::name) .def("__mul__", [](Solid2d & self, Solid2d & other) { return self*other; }) .def("__add__", [](Solid2d & self, Solid2d & other) { return self+other; }) .def("__sub__", [](Solid2d & self, Solid2d & other) { return self-other; }) - .def("Append", &Solid2d::Append) - .def("SetBC", &Solid2d::SetBC) + .def("Copy", [](Solid2d & self) -> Solid2d { return self; }) + .def("Move", &Solid2d::Move) + .def("Scale", &Solid2d::Scale) + .def("Rotate", [](Solid2d & self, optional rad, optional deg, Point<2> center ) + { + if(rad) + self.RotateRad(*rad, center); + if(deg) + self.RotateDeg(*deg, center); + return self; + }, py::arg("rad")=nullopt, py::arg("deg")=nullopt, py::arg("center")=Point<2>{0,0}) ; - m.def("Rectangle", [](double x0, double x1, double y0, double y1, string bc, string mat) - { return Rectangle(x0,x1,y0,y1,bc,mat); }, - py::arg("x0"), py::arg("x1"), py::arg("y0"), py::arg("y1"), py::arg("bc")="", py::arg("mat")="" + m.def("Rectangle", [](Point<2> pmin, Point<2> pmax, string bc, string mat) + { return Rectangle(pmin, pmax, bc,mat); }, + py::arg("pmin"), py::arg("pmax"), py::arg("bc")=BC_DEFAULT, py::arg("mat")=MAT_DEFAULT ); - m.def("Circle", Circle, py::arg("x"), py::arg("y"), py::arg("r"), py::arg("bc")="", py::arg("mat")=""); + m.def("Circle", Circle, py::arg("center"), py::arg("radius"), py::arg("bc")=BC_DEFAULT, py::arg("mat")=MAT_DEFAULT); py::class_(m, "CSG2d") .def(py::init<>()) From b14178b352eae72ea84588f6b49aeb8c882894ba Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Tue, 25 Aug 2020 10:29:38 +0200 Subject: [PATCH 129/384] csg2d - no bc in vertex, handle maxh --- libsrc/geom2d/csg2d.cpp | 23 ++++++++++++----------- libsrc/geom2d/csg2d.hpp | 30 +++++++++++++++++++++++++----- libsrc/geom2d/python_geom2d.cpp | 16 ++++++++++++---- 3 files changed, 49 insertions(+), 20 deletions(-) diff --git a/libsrc/geom2d/csg2d.cpp b/libsrc/geom2d/csg2d.cpp index 9a1a208c..07364024 100644 --- a/libsrc/geom2d/csg2d.cpp +++ b/libsrc/geom2d/csg2d.cpp @@ -98,7 +98,8 @@ Vertex * Vertex :: Insert(Point<2> p, double lam) current = current->next; auto pre = current->prev; - vnew->bc = pre->bc; + if(lam > -1.0) + vnew->info = pre->info; pre->next = vnew.get(); vnew->prev = pre; @@ -1148,7 +1149,7 @@ void CreateResult(Solid2d & sp, Solid2d & sr, bool UNION) auto & vnew = R.AppendVertex(*V); if ((status == EXIT) ^ UNION) { - vnew.bc = V->bc; + vnew.info = V->info; if(V->spline) vnew.spline = *V->spline; else @@ -1166,7 +1167,7 @@ void CreateResult(Solid2d & sp, Solid2d & sr, bool UNION) } else vnew.spline = nullopt; - vnew.bc = V->bc; + vnew.info = V->info; V->is_intersection = false; // mark visited vertices } if(V == I) @@ -1338,11 +1339,8 @@ Solid2d :: Solid2d(const Array, EdgeInfo>> & points, strin if(v->info.bc==BC_DEFAULT) v->info.bc = bc; - v->bc = v->info.bc; if(v->info.control_point) - { v->spline = Spline(*v, *v->info.control_point, *v->next); - } } polys.Append(l); @@ -1472,6 +1470,7 @@ shared_ptr CSG2d :: GenerateSplineGeometry() int bc; int p2; double weight; + double maxh = 1e99; }; auto geo = std::make_shared(); @@ -1575,11 +1574,13 @@ shared_ptr CSG2d :: GenerateSplineGeometry() ls.p2 = pi2; ls.weight = weight; - if(bcmap.count(p0.bc)==0) - bcmap[p0.bc] = bcmap.size()+1; + if(bcmap.count(p0.info.bc)==0) + bcmap[p0.info.bc] = bcmap.size()+1; - if(ls.bc==0 || p0.bc != BC_DEFAULT) - ls.bc = bcmap[p0.bc]; + if(ls.bc==0 || p0.info.bc != BC_DEFAULT) + ls.bc = bcmap[p0.info.bc]; + + ls.maxh = min(ls.maxh, p0.info.maxh); if(li!=ri) { @@ -1619,7 +1620,7 @@ shared_ptr CSG2d :: GenerateSplineGeometry() seg->bc = ls.bc; seg->reffak = 1; seg->copyfrom = -1; - seg->hmax = 1e99; + seg->hmax = ls.maxh; geo->AppendSegment(seg); } return geo; diff --git a/libsrc/geom2d/csg2d.hpp b/libsrc/geom2d/csg2d.hpp index c56859f8..a7a92b12 100644 --- a/libsrc/geom2d/csg2d.hpp +++ b/libsrc/geom2d/csg2d.hpp @@ -88,7 +88,7 @@ struct EdgeInfo if(other.bc != BC_DEFAULT) bc = other.bc; if(other.maxh != MAXH_DEFAULT) - maxh = other.maxh; + maxh = min(maxh, other.maxh); } }; @@ -107,8 +107,6 @@ struct Vertex : Point<2> IntersectionLabel label = NONE; // type of intersection vertex EntryExitLabel enex = NEITHER; // entry/exit "flag" - string bc = ""; - // In case the edge this - next is curved, store the spline information here optional spline = nullopt; EdgeInfo info; @@ -413,7 +411,7 @@ struct Loop Vertex & AppendVertex(const Vertex & v) { auto & vnew = Append( static_cast>(v), true ); - vnew.bc = v.bc; + vnew.info = v.info; if(v.spline) vnew.spline = *v.spline; return vnew; @@ -545,7 +543,7 @@ struct Loop void SetBC(string bc) { for(auto v : Vertices(ALL)) - v->bc = bc; + v->info.bc = bc; } size_t Size() const @@ -617,6 +615,28 @@ struct Solid2d { return RotateRad( ang/180.*M_PI ); } + + Solid2d & BC(string bc) + { + for(auto & p : polys) + for(auto v : p.Vertices(ALL)) + v->info.bc = bc; + return *this; + } + + Solid2d & Maxh(double maxh) + { + for(auto & p : polys) + for(auto v : p.Vertices(ALL)) + v->info.maxh = maxh; + return *this; + } + + Solid2d & Mat(string mat) + { + name = mat; + return *this; + } }; diff --git a/libsrc/geom2d/python_geom2d.cpp b/libsrc/geom2d/python_geom2d.cpp index 59de6c51..b44d44df 100644 --- a/libsrc/geom2d/python_geom2d.cpp +++ b/libsrc/geom2d/python_geom2d.cpp @@ -400,10 +400,18 @@ DLL_HEADER void ExportGeom2d(py::module &m) py::class_(m, "Solid2d") .def(py::init<>()) .def(py::init, EdgeInfo>>, std::string, std::string>(), py::arg("points"), py::arg("mat")=MAT_DEFAULT, py::arg("bc")=BC_DEFAULT) - .def_readwrite("name", &Solid2d::name) - .def("__mul__", [](Solid2d & self, Solid2d & other) { return self*other; }) - .def("__add__", [](Solid2d & self, Solid2d & other) { return self+other; }) - .def("__sub__", [](Solid2d & self, Solid2d & other) { return self-other; }) + + .def(py::self+py::self) + .def(py::self-py::self) + .def(py::self*py::self) + .def(py::self+=py::self) + .def(py::self-=py::self) + .def(py::self*=py::self) + + .def("Mat", &Solid2d::Mat) + .def("BC", &Solid2d::BC) + .def("Maxh", &Solid2d::Maxh) + .def("Copy", [](Solid2d & self) -> Solid2d { return self; }) .def("Move", &Solid2d::Move) .def("Scale", &Solid2d::Scale) From 89c33f5b288225c17a2627e270e37919cbcd7682 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Tue, 25 Aug 2020 10:59:48 +0200 Subject: [PATCH 130/384] csg2d GenerateMesh in Python, fix arguments for Rectangle/Circle --- libsrc/geom2d/python_geom2d.cpp | 34 ++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/libsrc/geom2d/python_geom2d.cpp b/libsrc/geom2d/python_geom2d.cpp index b44d44df..aa3b77c4 100644 --- a/libsrc/geom2d/python_geom2d.cpp +++ b/libsrc/geom2d/python_geom2d.cpp @@ -373,9 +373,8 @@ DLL_HEADER void ExportGeom2d(py::module &m) }) ) - // If we change to c++17 this can become optional .def("GenerateMesh", [](shared_ptr self, - MeshingParameters* pars, py::kwargs kwargs) + optional pars, py::kwargs kwargs) { MeshingParameters mp; if(pars) mp = *pars; @@ -391,7 +390,7 @@ DLL_HEADER void ExportGeom2d(py::module &m) if(result != 0) throw Exception("Meshing failed!"); return mesh; - }, py::arg("mp") = nullptr, + }, py::arg("mp") = nullopt, py::call_guard(), meshingparameter_description.c_str()) .def("_SetDomainTensorMeshing", &SplineGeometry2d::SetDomainTensorMeshing) @@ -423,19 +422,40 @@ DLL_HEADER void ExportGeom2d(py::module &m) self.RotateDeg(*deg, center); return self; }, py::arg("rad")=nullopt, py::arg("deg")=nullopt, py::arg("center")=Point<2>{0,0}) + ; - m.def("Rectangle", [](Point<2> pmin, Point<2> pmax, string bc, string mat) - { return Rectangle(pmin, pmax, bc,mat); }, - py::arg("pmin"), py::arg("pmax"), py::arg("bc")=BC_DEFAULT, py::arg("mat")=MAT_DEFAULT + m.def("Rectangle", [](Point<2> pmin, Point<2> pmax, string mat, string bc) + { return Rectangle(pmin, pmax, mat, bc); }, + py::arg("pmin"), py::arg("pmax"), py::arg("mat")=MAT_DEFAULT, py::arg("bc")=BC_DEFAULT ); - m.def("Circle", Circle, py::arg("center"), py::arg("radius"), py::arg("bc")=BC_DEFAULT, py::arg("mat")=MAT_DEFAULT); + m.def("Circle", Circle, py::arg("center"), py::arg("radius"), py::arg("mat")=MAT_DEFAULT, py::arg("bc")=BC_DEFAULT); py::class_(m, "CSG2d") .def(py::init<>()) .def("GenerateSplineGeometry", &CSG2d::GenerateSplineGeometry) .def("Add", &CSG2d::Add) + .def("GenerateMesh", [](CSG2d & self, optional pars, py::kwargs kwargs) + { + MeshingParameters mp; + if(pars) mp = *pars; + { + py::gil_scoped_acquire aq; + CreateMPfromKwargs(mp, kwargs); + } + auto mesh = make_shared(); + auto geo = self.GenerateSplineGeometry(); + mesh->SetGeometry(geo); + SetGlobalMesh (mesh); + ng_geometry = geo; + auto result = geo->GenerateMesh(mesh, mp); + if(result != 0) + throw Exception("Meshing failed!"); + return mesh; + }, py::arg("mp") = nullopt, + py::call_guard(), + meshingparameter_description.c_str()) ; py::class_(m, "EdgeInfo") From 7aab695f046db1a1271881c9605408ac25bb71f0 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Tue, 25 Aug 2020 11:26:06 +0200 Subject: [PATCH 131/384] csg2d - skip degenerated solids --- libsrc/geom2d/csg2d.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/libsrc/geom2d/csg2d.cpp b/libsrc/geom2d/csg2d.cpp index 07364024..d1871166 100644 --- a/libsrc/geom2d/csg2d.cpp +++ b/libsrc/geom2d/csg2d.cpp @@ -1538,7 +1538,7 @@ shared_ptr CSG2d :: GenerateSplineGeometry() for(auto & s : solids) { dom++; - geo->SetMaterial(dom, s.name); + bool is_solid_degenerated = true; // Don't create new domain for degenerated solids for(auto & poly : s.polys) { for(auto v : poly.Vertices(ALL)) @@ -1588,9 +1588,15 @@ shared_ptr CSG2d :: GenerateSplineGeometry() ls.left = dom; else ls.right = dom; + + is_solid_degenerated = false; } } } + if(!is_solid_degenerated) + geo->SetMaterial(dom, s.name); + else + dom--; // degenerated solid, use same domain index again } for(auto & [name, bc] : bcmap) From 78d047999308e3e2ac6c1b7f27331defd990de42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20Sch=C3=B6berl?= Date: Tue, 25 Aug 2020 18:18:31 +0200 Subject: [PATCH 132/384] can convert to mpi4py - communicator --- libsrc/meshing/python_mesh.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libsrc/meshing/python_mesh.cpp b/libsrc/meshing/python_mesh.cpp index 64e3e0c8..07856c1c 100644 --- a/libsrc/meshing/python_mesh.cpp +++ b/libsrc/meshing/python_mesh.cpp @@ -122,6 +122,7 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m) { return NgMPI_Comm(comm); })) + .def_property_readonly ("mpi4py", [] (NgMPI_Comm comm) { return mpi4py_comm(comm); }) #endif // NG_MPI4PY .def_property_readonly ("rank", &NgMPI_Comm::Rank) .def_property_readonly ("size", &NgMPI_Comm::Size) From 9968037361e99eb879423b3a0b07ec33b7ac7f26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20Sch=C3=B6berl?= Date: Fri, 28 Aug 2020 08:47:33 +0200 Subject: [PATCH 133/384] move semantics to table, PNums to LineSegments --- libsrc/core/table.hpp | 7 +++++++ libsrc/general/table.hpp | 11 +++++++++++ libsrc/meshing/meshtype.hpp | 4 ++++ 3 files changed, 22 insertions(+) diff --git a/libsrc/core/table.hpp b/libsrc/core/table.hpp index 537ea2a4..8a565a44 100644 --- a/libsrc/core/table.hpp +++ b/libsrc/core/table.hpp @@ -405,6 +405,13 @@ public: /// Creates table with a priori fixed entry sizes. DynamicTable (const Array & entrysizes) : BaseDynamicTable (entrysizes, sizeof(T)) { ; } + + DynamicTable & operator= (DynamicTable && tab2) + { + Swap (data, tab2.data); + Swap (oneblock, tab2.oneblock); + return *this; + } /// Inserts element acont into row i. Does not test if already used. void Add (int i, const T & acont) diff --git a/libsrc/general/table.hpp b/libsrc/general/table.hpp index 7d2f6999..832fc751 100644 --- a/libsrc/general/table.hpp +++ b/libsrc/general/table.hpp @@ -114,11 +114,22 @@ public: /// Creates table of size size inline TABLE (int size) : BASE_TABLE (size) { ; } + TABLE (TABLE && tab2) + : BASE_TABLE(move(tab2)) + { } + /// Creates fixed maximal element size table inline TABLE (const NgFlatArray & entrysizes) : BASE_TABLE (NgFlatArray (entrysizes.Size(), const_cast(&entrysizes[BASE])), sizeof(T)) { ; } + + TABLE & operator= (TABLE && tab2) + { + BASE_TABLE::operator=(move(tab2)); + return *this; + } + /// Changes Size of table to size, deletes data inline void SetSize (int size) diff --git a/libsrc/meshing/meshtype.hpp b/libsrc/meshing/meshtype.hpp index 4071df4b..30c269e6 100644 --- a/libsrc/meshing/meshtype.hpp +++ b/libsrc/meshing/meshtype.hpp @@ -1062,6 +1062,10 @@ namespace netgen return pnums[2].IsValid() ? 3 : 2; } + auto PNums() const { return FlatArray (GetNP(), &pnums[0]); } + auto PNums() { return FlatArray (GetNP(), &pnums[0]); } + + ELEMENT_TYPE GetType() const { return pnums[2].IsValid() ? SEGMENT3 : SEGMENT; From 122a9339650bbce9cad2c2b4e19cfdc44303a283 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20Sch=C3=B6berl?= Date: Fri, 28 Aug 2020 08:57:30 +0200 Subject: [PATCH 134/384] parallel enumerate after refinement --- libsrc/meshing/meshclass.cpp | 6 +- libsrc/meshing/parallelmesh.cpp | 9 +- libsrc/meshing/paralleltop.cpp | 414 ++++++++++++++++++++++++++++++-- libsrc/meshing/paralleltop.hpp | 11 +- libsrc/meshing/refine.cpp | 11 + 5 files changed, 425 insertions(+), 26 deletions(-) diff --git a/libsrc/meshing/meshclass.cpp b/libsrc/meshing/meshclass.cpp index 7006ea07..6bcd6e0c 100644 --- a/libsrc/meshing/meshclass.cpp +++ b/libsrc/meshing/meshclass.cpp @@ -1301,8 +1301,8 @@ namespace netgen // merge points - Array globnum(points.Size()); - int maxglob = 0; + Array globnum(points.Size()); + PointIndex maxglob = -1; for (auto pi : Range(points)) { globnum[pi] = partop.GetGlobalPNum(pi); @@ -1319,7 +1319,7 @@ namespace netgen } else { - Array globnumi; + Array globnumi; Array pointsi; Array globpoints(numglob); for (int j = 1; j < comm.Size(); j++) diff --git a/libsrc/meshing/parallelmesh.cpp b/libsrc/meshing/parallelmesh.cpp index b17490ae..62f482c1 100644 --- a/libsrc/meshing/parallelmesh.cpp +++ b/libsrc/meshing/parallelmesh.cpp @@ -57,6 +57,7 @@ namespace netgen if (id == 0) { paralleltop -> SetNV (GetNV()); + paralleltop -> SetNV_Loc2Glob (GetNV()); paralleltop -> SetNE (GetNE()); paralleltop -> SetNSegm (GetNSeg()); paralleltop -> SetNSE (GetNSE()); @@ -732,7 +733,9 @@ namespace netgen for (auto t : point_types) { MPI_Type_free(&t); } - + paralleltop -> SetNV_Loc2Glob (0); + paralleltop -> SetNV (0); + paralleltop -> EnumeratePointsGlobally(); PrintMessage ( 3, "Sending names"); sendrequests.SetSize(3*ntasks); @@ -859,6 +862,7 @@ namespace netgen int numvert = verts.Size(); paralleltop -> SetNV (numvert); + paralleltop -> SetNV_Loc2Glob (numvert); // INDEX_CLOSED_HASHTABLE glob2loc_vert_ht (3*numvert+1); INDEX_HASHTABLE glob2loc_vert_ht (3*numvert+1); @@ -1020,7 +1024,8 @@ namespace netgen } } - + paralleltop -> SetNV_Loc2Glob (0); + paralleltop -> EnumeratePointsGlobally(); /** Recv bc-names **/ ArrayMem nnames{0,0,0,0}; // MPI_Recv(nnames, 4, MPI_INT, 0, MPI_TAG_MESH+6, comm, MPI_STATUS_IGNORE); diff --git a/libsrc/meshing/paralleltop.cpp b/libsrc/meshing/paralleltop.cpp index 91c5f9ad..f2337b18 100644 --- a/libsrc/meshing/paralleltop.cpp +++ b/libsrc/meshing/paralleltop.cpp @@ -4,6 +4,29 @@ #include #include "paralleltop.hpp" +namespace ngcore +{ + + template + auto Max (FlatArray array) -> T + { + T max = std::numeric_limits::min(); + for (auto & v : array) + if (v > max) max = v; + return max; + } + /* + template + auto Max (FlatArray array, TB initial) -> T + { + T max = initial; + for (auto & v : array) + if (v > max) max = v; + return max; + } + */ +} + namespace netgen { @@ -57,17 +80,27 @@ namespace netgen void ParallelMeshTopology :: EnumeratePointsGlobally () { - auto nv = loc2distvert.Size(); auto comm = mesh.GetCommunicator(); auto rank = comm.Rank(); - // if (rank == 0) - // nv = 0; - glob_vert.SetSize (nv); - glob_vert = -1; - int num_master_points = 0; + size_t oldnv = glob_vert.Size(); + size_t nv = loc2distvert.Size(); + *testout << "enumerate globally, loc2distvert.size = " << loc2distvert.Size() + << ", glob_vert.size = " << glob_vert.Size() << endl; + + // *testout << "old glob_vert = " << endl << glob_vert << endl; - for (auto i : Range(nv)) + if (rank == 0) + nv = 0; + + IntRange newvr(oldnv, nv); // new vertex range + + glob_vert.SetSize (nv); + glob_vert.Range(newvr) = -1; + + int num_master_points = 0; + + for (auto i : newvr) { auto dps = GetDistantPNums(i); // check sorted: @@ -77,11 +110,16 @@ namespace netgen if (dps.Size() == 0 || dps[0] > comm.Rank()) glob_vert[i] = num_master_points++; } - + + *testout << "nummaster = " << num_master_points << endl; + Array first_master_point(comm.Size()); comm.AllGather (num_master_points, first_master_point); - - size_t num_glob_points = 0; + auto max_oldv = comm.AllReduce (Max (glob_vert.Range(0, oldnv)), MPI_MAX); + if (comm.AllReduce (oldnv, MPI_SUM) == 0) + max_oldv = PointIndex::BASE-1; + + size_t num_glob_points = max_oldv+1; // PointIndex::BASE; for (int i = 0; i < comm.Size(); i++) { int cur = first_master_point[i]; @@ -89,7 +127,7 @@ namespace netgen num_glob_points += cur; } - for (auto i : Range(nv)) + for (auto i : newvr) if (glob_vert[i] != -1) glob_vert[i] += first_master_point[comm.Rank()]; @@ -100,7 +138,7 @@ namespace netgen nrecv = 0; /** Count send/recv size **/ - for (auto i : Range(nv)) + for (auto i : newvr) { auto dps = GetDistantPNums(i); if (!dps.Size()) continue; @@ -116,7 +154,7 @@ namespace netgen /** Fill send_data **/ nsend = 0; - for (auto i : Range(nv)) + for (auto i : newvr) { auto dps = GetDistantPNums(i); if (dps.Size() && rank < dps[0]) @@ -138,7 +176,7 @@ namespace netgen Array cnt(comm.Size()); cnt = 0; - for (auto i : Range(nv)) + for (auto i : newvr) { auto dps = GetDistantPNums(i); if (dps.Size() > 0 && dps[0] < comm.Rank()) @@ -146,13 +184,98 @@ namespace netgen int master = comm.Size(); for (int j = 0; j < dps.Size(); j++) master = min (master, dps[j]); + if (master != dps[0]) + cout << "master not the first one !" << endl; glob_vert[i] = recv_data[master][cnt[master]++]; } } + /* if (PointIndex::BASE==1) for (auto & i : glob_vert) i++; + */ + + /* + cout << "check ordering: " << endl; + for (int i = 0; i < glob_vert.Size()-1; i++) + if (glob_vert[i] > glob_vert[i+1]) + cout << "wrong ordering" << endl; + */ + + // reorder following global ordering: + Array index0(glob_vert.Size()); + for (int pi : Range(index0)) + index0[pi] = pi; + QuickSortI (FlatArray (glob_vert), index0); + + comm.Barrier(); + for (int i = 0; i+1 < glob_vert.Size(); i++) + if (glob_vert[index0[i]] > glob_vert[index0[i+1]]) + cout << "wrong ordering" << endl; + comm.Barrier(); + + if (rank != 0) + { + Array index(index0.Size()); + for (int i = 0; i < index0.Size(); i++) + index[i+PointIndex::BASE] = index0[i]+PointIndex::BASE; + Array inv_index(index0.Size()); + for (int i = 0; i < index0.Size(); i++) + inv_index[index0[i]+PointIndex::BASE] = i+PointIndex::BASE; + + for (auto & el : mesh.VolumeElements()) + for (PointIndex & pi : el.PNums()) + pi = inv_index[pi]; + for (auto & el : mesh.SurfaceElements()) + for (PointIndex & pi : el.PNums()) + pi = inv_index[pi]; + for (auto & el : mesh.LineSegments()) + for (PointIndex & pi : el.PNums()) + pi = inv_index[pi]; + + // auto hpoints (mesh.Points()); + Array hpoints { mesh.Points() }; + for (PointIndex pi : Range(mesh.Points())) + mesh.Points()[inv_index[pi]] = hpoints[pi]; + + if (mesh.mlbetweennodes.Size() == mesh.Points().Size()) + { + cout << "take care of multigrid table" << endl; + NgArray,PointIndex::BASE> hml { mesh.mlbetweennodes }; + for (PointIndex pi : Range(mesh.Points())) + mesh.mlbetweennodes[inv_index[pi]] = hml[pi]; + } + + + + // *testout << "index0 = " << endl << index0 << endl; + // *testout << "loc2distvertold = " << endl; + // for (auto i : Range(index0)) + // *testout << "l " << i << " globi "<< glob_vert[i] << " dist = " << loc2distvert[i] << endl; + DynamicTable oldtable(loc2distvert.Size()); + for (size_t i = 0; i < loc2distvert.Size(); i++) + for (auto val : loc2distvert[i]) + oldtable.Add (i, val); + loc2distvert = DynamicTable (oldtable.Size()); + for (size_t i = 0; i < oldtable.Size(); i++) + for (auto val : oldtable[index0[i]]) + loc2distvert.Add (i, val); + + Array hglob_vert(glob_vert); + for (int i = 0; i < index0.Size(); i++) + glob_vert[i] = hglob_vert[index0[i]]; + + // *testout << "loc2distvertnew = " << endl; + // for (auto i : Range(index0)) + // *testout << "l " << i << " globi "<< glob_vert[i] << " dist = " << loc2distvert[i] << endl; + } + + for (int i = 0; i+1 < glob_vert.Size(); i++) + if (glob_vert[i] > glob_vert[i+1]) + cout << "wrong ordering of globvert" << endl; + + // *testout << "new glob_vert = " << glob_vert << endl; } @@ -181,11 +304,26 @@ namespace netgen loc2distedge.Add (locnum-1, dest); } - void ParallelMeshTopology :: SetNV (int anv) + void ParallelMeshTopology :: SetNV_Loc2Glob (int anv) { glob_vert.SetSize(anv); glob_vert = -1; - loc2distvert.ChangeSize (anv); + } + + void ParallelMeshTopology :: SetNV (int anv) + { + // glob_vert.SetSize(anv); + // glob_vert = -1; + // loc2distvert.ChangeSize (anv); + + DynamicTable oldtable(loc2distvert.Size()); + for (size_t i = 0; i < loc2distvert.Size(); i++) + for (auto val : loc2distvert[i]) + oldtable.Add (i, val); + loc2distvert = DynamicTable (anv); + for (size_t i = 0; i < min(anv, oldtable.Size()); i++) + for (auto val : oldtable[i]) + loc2distvert.Add (i, val); } void ParallelMeshTopology :: SetNE ( int ane ) @@ -303,7 +441,233 @@ namespace netgen is_updated = true; } + void ParallelMeshTopology :: IdentifyVerticesAfterRefinement() + { + static Timer t("ParallelTopology::UpdateCoarseGrid"); RegionTimer r(t); + // cout << "UpdateCoarseGrid" << endl; + // if (is_updated) return; + NgMPI_Comm comm = mesh.GetCommunicator(); + int id = comm.Rank(); + int ntasks = comm.Size(); + + if (ntasks == 1) return; + + Reset(); + static int timer = NgProfiler::CreateTimer ("UpdateCoarseGrid"); + NgProfiler::RegionTimer reg(timer); + + + (*testout) << "UPDATE COARSE GRID PARALLEL TOPOLOGY " << endl; + if (id == 0) + PrintMessage (1, "update parallel topology"); + + + // UpdateCoarseGridGlobal(); + + + + // MPI_Barrier (MPI_COMM_WORLD); + + MPI_Group MPI_GROUP_comm; + MPI_Group MPI_LocalGroup; + MPI_Comm MPI_LocalComm1; + + int process_ranks[] = { 0 }; + MPI_Comm_group (comm, &MPI_GROUP_comm); + MPI_Group_excl (MPI_GROUP_comm, 1, process_ranks, &MPI_LocalGroup); + MPI_Comm_create (comm, MPI_LocalGroup, &MPI_LocalComm1); + + if (id == 0) + { + // SetNV(0); + // EnumeratePointsGlobally(); + return; + } + + NgMPI_Comm MPI_LocalComm(MPI_LocalComm1); + + + const MeshTopology & topology = mesh.GetTopology(); + + NgArray cnt_send(ntasks-1); + + + + + // update new vertices after mesh-refinement + if (mesh.mlbetweennodes.Size() > 0) + { + // *testout << "have to identify new vertices, nv = " << mesh.GetNV() << endl; + + // cout << "UpdateCoarseGrid - vertices" << endl; + int newnv = mesh.mlbetweennodes.Size(); + + // loc2distvert.ChangeSize(mesh.mlbetweennodes.Size()); + DynamicTable oldtable(loc2distvert.Size()); + for (size_t i = 0; i < loc2distvert.Size(); i++) + for (auto val : loc2distvert[i]) + oldtable.Add (i, val); + loc2distvert = DynamicTable (mesh.mlbetweennodes.Size()); + for (size_t i = 0; i < min(loc2distvert.Size(), oldtable.Size()); i++) + for (auto val : oldtable[i]) + loc2distvert.Add (i, val); + + *testout << "extended loc2distver = " << endl << loc2distvert << endl; + + /* + for (PointIndex pi = PointIndex::BASE; pi < newnv+PointIndex::BASE; pi++) + { + PointIndex v1 = mesh.mlbetweennodes[pi][0]; + PointIndex v2 = mesh.mlbetweennodes[pi][1]; + if (mesh.mlbetweennodes[pi][0] != PointIndex::BASE-1) + for (int dest = 1; dest < ntasks; dest++) + if (IsExchangeVert (dest, v1) && IsExchangeVert (dest, v2)) + SetDistantPNum(dest, pi); + } + */ + + bool changed = true; + while (changed) + { + changed = false; + + // build exchange vertices + cnt_send = 0; + for (PointIndex pi : mesh.Points().Range()) + for (int dist : GetDistantPNums(pi-PointIndex::BASE)) + cnt_send[dist-1]++; + TABLE dest2vert(cnt_send); + for (PointIndex pi : mesh.Points().Range()) + for (int dist : GetDistantPNums(pi-PointIndex::BASE)) + dest2vert.Add (dist-1, pi); + + for (PointIndex pi = PointIndex::BASE; pi < newnv+PointIndex::BASE; pi++) + { + PointIndex v1 = mesh.mlbetweennodes[pi][0]; + PointIndex v2 = mesh.mlbetweennodes[pi][1]; + if (mesh.mlbetweennodes[pi][0] != PointIndex::BASE-1) + // for (int dest = 1; dest < ntasks; dest++) + for (int dest : GetDistantPNums(v1-PointIndex::BASE)) + if (IsExchangeVert (dest, v1) && IsExchangeVert (dest, v2)) + cnt_send[dest-1]++; + } + + TABLE dest2pair(cnt_send); + // for (int dest = 1; dest < ntasks; dest++) + for (PointIndex pi = PointIndex::BASE; pi < newnv+PointIndex::BASE; pi++) + { + PointIndex v1 = mesh.mlbetweennodes[pi][0]; + PointIndex v2 = mesh.mlbetweennodes[pi][1]; + if (mesh.mlbetweennodes[pi][0] != PointIndex::BASE-1) + for (int dest : GetDistantPNums(v1-PointIndex::BASE)) + if (IsExchangeVert (dest, v1) && IsExchangeVert (dest, v2)) + dest2pair.Add (dest-1, pi); + } + + cnt_send = 0; + int v1, v2; + for (PointIndex pi = PointIndex::BASE; pi < newnv+PointIndex::BASE; pi++) + { + PointIndex v1 = mesh.mlbetweennodes[pi][0]; + PointIndex v2 = mesh.mlbetweennodes[pi][1]; + if (mesh.mlbetweennodes[pi][0] != PointIndex::BASE-1) + for (int dest : GetDistantPNums(v1-PointIndex::BASE)) + if (IsExchangeVert(dest, v2)) + cnt_send[dest-1]+=2; + } + + TABLE send_verts(cnt_send); + + NgArray loc2exchange(mesh.GetNV()); + for (int dest = 1; dest < ntasks; dest++) + if (dest != id) + { + loc2exchange = -1; + int cnt = 0; + /* + for (PointIndex pi : mesh.Points().Range()) + if (IsExchangeVert(dest, pi)) + loc2exchange[pi] = cnt++; + */ + for (PointIndex pi : dest2vert[dest-1]) + loc2exchange[pi] = cnt++; + + // for (PointIndex pi = PointIndex::BASE; pi < newnv+PointIndex::BASE; pi++) + for (PointIndex pi : dest2pair[dest-1]) + { + PointIndex v1 = mesh.mlbetweennodes[pi][0]; + PointIndex v2 = mesh.mlbetweennodes[pi][1]; + if (mesh.mlbetweennodes[pi][0] != PointIndex::BASE-1) + if (IsExchangeVert (dest, v1) && IsExchangeVert (dest, v2)) + { + send_verts.Add (dest-1, loc2exchange[v1]); + send_verts.Add (dest-1, loc2exchange[v2]); + } + } + } + + TABLE recv_verts(ntasks-1); + MyMPI_ExchangeTable (send_verts, recv_verts, MPI_TAG_MESH+9, MPI_LocalComm); + + for (int dest = 1; dest < ntasks; dest++) + if (dest != id) + { + loc2exchange = -1; + int cnt = 0; + /* + for (PointIndex pi : mesh.Points().Range()) + if (IsExchangeVert(dest, pi)) + loc2exchange[pi] = cnt++; + */ + for (PointIndex pi : dest2vert[dest-1]) + loc2exchange[pi] = cnt++; + + NgFlatArray recvarray = recv_verts[dest-1]; + for (int ii = 0; ii < recvarray.Size(); ii+=2) + for (PointIndex pi : dest2pair[dest-1]) + // for (PointIndex pi = PointIndex::BASE; pi < newnv+PointIndex::BASE; pi++) + { + PointIndex v1 = mesh.mlbetweennodes[pi][0]; + PointIndex v2 = mesh.mlbetweennodes[pi][1]; + if (mesh.mlbetweennodes[pi][0] != PointIndex::BASE-1) + { + INDEX_2 re(recvarray[ii], recvarray[ii+1]); + INDEX_2 es(loc2exchange[v1], loc2exchange[v2]); + if (es == re && !IsExchangeVert(dest, pi)) + { + SetDistantPNum(dest, pi); + changed = true; + } + } + } + } + } + } + + NgArray sendarray, recvarray; + // cout << "UpdateCoarseGrid - edges" << endl; + + // static int timerv = NgProfiler::CreateTimer ("UpdateCoarseGrid - ex vertices"); + static int timere = NgProfiler::CreateTimer ("UpdateCoarseGrid - ex edges"); + static int timerf = NgProfiler::CreateTimer ("UpdateCoarseGrid - ex faces"); + + + NgProfiler::StartTimer (timere); + + // build exchange vertices + cnt_send = 0; + for (PointIndex pi : mesh.Points().Range()) + for (int dist : GetDistantPNums(pi-PointIndex::BASE)) + cnt_send[dist-1]++; + TABLE dest2vert(cnt_send); + for (PointIndex pi : mesh.Points().Range()) + for (int dist : GetDistantPNums(pi-PointIndex::BASE)) + dest2vert.Add (dist-1, pi); + + MPI_Group_free(&MPI_LocalGroup); + // MPI_Comm_free(&MPI_LocalComm); + } void ParallelMeshTopology :: UpdateCoarseGrid () @@ -354,13 +718,25 @@ namespace netgen NgArray cnt_send(ntasks-1); - +#ifdef NONE // update new vertices after mesh-refinement if (mesh.mlbetweennodes.Size() > 0) { // cout << "UpdateCoarseGrid - vertices" << endl; int newnv = mesh.mlbetweennodes.Size(); - loc2distvert.ChangeSize(mesh.mlbetweennodes.Size()); + + // loc2distvert.ChangeSize(mesh.mlbetweennodes.Size()); + DynamicTable oldtable(loc2distvert.Size()); + for (size_t i = 0; i < loc2distvert.Size(); i++) + for (auto val : loc2distvert[i]) + oldtable.Add (i, val); + loc2distvert = DynamicTable (mesh.mlbetweennodes.Size()); + for (size_t i = 0; i < min(loc2distvert.Size(), oldtable.Size()); i++) + for (auto val : oldtable[i]) + loc2distvert.Add (i, val); + + + /* for (PointIndex pi = PointIndex::BASE; pi < newnv+PointIndex::BASE; pi++) { @@ -491,7 +867,9 @@ namespace netgen } } } +#endif + NgArray sendarray, recvarray; // cout << "UpdateCoarseGrid - edges" << endl; diff --git a/libsrc/meshing/paralleltop.hpp b/libsrc/meshing/paralleltop.hpp index 6f223928..8589801b 100644 --- a/libsrc/meshing/paralleltop.hpp +++ b/libsrc/meshing/paralleltop.hpp @@ -14,10 +14,12 @@ namespace netgen each row of the table corresponds to one vertex each row contains a list of pairs (procnr, dist_vnum) */ + + DynamicTable loc2distvert; + TABLE loc2distedge, loc2distface; - TABLE loc2distvert, loc2distedge, loc2distface; - - NgArray glob_vert, glob_edge, glob_face; + Array glob_vert; + NgArray glob_edge, glob_face; NgArray glob_el, glob_surfel, glob_segm; bool is_updated; @@ -32,12 +34,14 @@ namespace netgen void UpdateCoarseGrid(); void UpdateCoarseGridGlobal(); + void IdentifyVerticesAfterRefinement(); // bool DoCoarseUpdate() const { return !coarseupdate; } /// set number of local vertices, reset sizes of loc2dist_vert, isexchangevert... void SetNV (int anv); + void SetNV_Loc2Glob (int anv); void SetNE (int ane); void SetNSE (int anse); void SetNSegm (int anseg); @@ -117,6 +121,7 @@ namespace netgen FlatArray GetDistantFaceNums (int locnum) const { return loc2distface[locnum]; } FlatArray GetDistantEdgeNums (int locnum) const { return loc2distedge[locnum]; } + [[deprecated("Use GetDistantPNums(..).Contains instead!")]] bool IsExchangeVert (int dest, int vnum) const { return loc2distvert[vnum-1].Contains (dest); diff --git a/libsrc/meshing/refine.cpp b/libsrc/meshing/refine.cpp index 6f9e4585..5c92a95d 100644 --- a/libsrc/meshing/refine.cpp +++ b/libsrc/meshing/refine.cpp @@ -738,6 +738,17 @@ namespace netgen PrintMessage (5, "have 3d elements"); mesh.ComputeNVertices(); mesh.RebuildSurfaceElementLists(); + + +#ifdef PARALLEL + if (mesh.GetCommunicator().Size() > 1) + { + mesh.GetParallelTopology().IdentifyVerticesAfterRefinement(); + mesh.GetCommunicator().Barrier(); + mesh.GetParallelTopology().EnumeratePointsGlobally(); + } +#endif + PrintMessage (5, "mesh updates complete"); return; From ac87e9b62cc77bf373b00e1e7d547b26b1cb7bc5 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Fri, 28 Aug 2020 14:21:45 +0200 Subject: [PATCH 135/384] csg2d - proper +=/-=/*= operator --- libsrc/geom2d/csg2d.cpp | 6 +++--- libsrc/geom2d/csg2d.hpp | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/libsrc/geom2d/csg2d.cpp b/libsrc/geom2d/csg2d.cpp index d1871166..af05475a 100644 --- a/libsrc/geom2d/csg2d.cpp +++ b/libsrc/geom2d/csg2d.cpp @@ -1380,19 +1380,19 @@ Solid2d Solid2d :: operator-(const Solid2d & other_) const return res; } -Solid2d Solid2d :: operator+=(const Solid2d & other) +Solid2d & Solid2d :: operator+=(const Solid2d & other) { *this = *this + other; return *this; } -Solid2d Solid2d :: operator*=(const Solid2d & other) +Solid2d & Solid2d :: operator*=(const Solid2d & other) { *this = *this * other; return *this; } -Solid2d Solid2d :: operator-=(const Solid2d & other) +Solid2d & Solid2d :: operator-=(const Solid2d & other) { *this = *this - other; return *this; diff --git a/libsrc/geom2d/csg2d.hpp b/libsrc/geom2d/csg2d.hpp index a7a92b12..42054bd5 100644 --- a/libsrc/geom2d/csg2d.hpp +++ b/libsrc/geom2d/csg2d.hpp @@ -575,9 +575,9 @@ struct Solid2d Solid2d operator-(const Solid2d & other) const; Solid2d& operator=(const Solid2d & other) = default; - Solid2d operator+=(const Solid2d & other); - Solid2d operator*=(const Solid2d & other); - Solid2d operator-=(const Solid2d & other); + Solid2d& operator+=(const Solid2d & other); + Solid2d& operator*=(const Solid2d & other); + Solid2d& operator-=(const Solid2d & other); void Append( const Loop & poly ) { From f559cdef16c94ef88be0cee244bfd9ae0d76e853 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Fri, 28 Aug 2020 14:22:39 +0200 Subject: [PATCH 136/384] csg2d - better IsInside() check for splines --- libsrc/geom2d/csg2d.cpp | 63 +++++++++++++++++++++++++++++++++++------ libsrc/geom2d/csg2d.hpp | 8 +----- 2 files changed, 56 insertions(+), 15 deletions(-) diff --git a/libsrc/geom2d/csg2d.cpp b/libsrc/geom2d/csg2d.cpp index af05475a..31f707e5 100644 --- a/libsrc/geom2d/csg2d.cpp +++ b/libsrc/geom2d/csg2d.cpp @@ -1322,6 +1322,42 @@ Solid2d ClipSolids ( Solid2d s1, Solid2d s2, bool intersect) return res; } +bool Loop :: IsInside( Point<2> r ) const +{ + int w = 0; + for(auto e : Edges(ALL)) + { + int w_simple = CalcSide(*e.v0, *e.v1, r); + if(!e.v0->spline) + w += w_simple; + else + { + auto s = *e.v0->spline; + auto s0 = s.StartPI(); + auto s1 = s.TangentPoint(); + auto s2 = s.EndPI(); + if(!IsInsideTrig( {s0, s1, s2} , r )) + w += w_simple; + else + { + // r close to spline, need exact test + // idea: compute weight, such that r lies on spline + // weight increases -> same side of spline as control point, simple test gives correct result + // weight decreases -> opposite side of spline as control point, adding control point to test polygon gives correct result + double old_weight = s.GetWeight(); + ComputeWeight( s, r ); + double new_weight = s.GetWeight(); + + if(new_weight >= old_weight) + w += w_simple; + else + w += CalcSide(s0, s1, r) + CalcSide(s1, s2, r); + } + } + } + return ( (w % 2) != 0 ); +} + Solid2d :: Solid2d(const Array, EdgeInfo>> & points, string name_, string bc) : name(name_) { @@ -1370,12 +1406,6 @@ Solid2d Solid2d :: operator-(const Solid2d & other_) const other.Append(RectanglePoly(-1e8, 1e8, -1e8, 1e8, "JUST_FOR_CLIPPING")); auto res = ClipSolids(*this, other); - for (auto i : Range(other.polys)) - { - auto & first = *other.polys[i].first; - if(first[0] == -1e8) - other.polys.DeleteElement(i); - } res.name = name; return res; } @@ -1432,23 +1462,40 @@ bool Solid2d :: IsInside( Point<2> r ) const { int w = 0; for(auto & poly : polys) - for(auto v : poly.Vertices(ALL)) - w += CalcSide(*v, *v->next, r); + w += poly.IsInside(r); return ( (w % 2) != 0 ); } bool Solid2d :: IsLeftInside( const Vertex & p0 ) { auto & p1 = *p0.next; + if(p0.spline) + { + auto s = *p0.spline; + auto v = s.GetTangent(0.5); + auto n = Vec<2>{v[1], -v[0]}; + auto q = s.GetPoint(0.5) + 1e-6*n; + return IsInside(q); + } auto v = p1-p0; auto n = Vec<2>{v[1], -v[0]}; auto q = p0 + 0.5*v + 1e-6*n; + return IsInside(q); } bool Solid2d :: IsRightInside( const Vertex & p0 ) { auto & p1 = *p0.next; + if(p0.spline) + { + auto s = *p0.spline; + auto v = s.GetTangent(0.5); + auto n = Vec<2>{-v[1], v[0]}; + auto q = s.GetPoint(0.5) + 1e-6*n; + return IsInside(q); + } + auto v = p1-p0; auto n = Vec<2>{-v[1], v[0]}; auto q = p0 + 0.5*v + 1e-6*n; diff --git a/libsrc/geom2d/csg2d.hpp b/libsrc/geom2d/csg2d.hpp index 42054bd5..4fe00fe0 100644 --- a/libsrc/geom2d/csg2d.hpp +++ b/libsrc/geom2d/csg2d.hpp @@ -447,13 +447,7 @@ struct Loop v->prev->pnext = std::move(v->pnext); } - bool IsInside( Point<2> r ) const - { - int w = 0; - for(auto e : Edges(ALL)) - w += CalcSide(*e.v0, *e.v1, r); - return ( (w % 2) != 0 ); - } + bool IsInside( Point<2> r ) const; EdgeIterator Edges(IteratorType iterType) const { From 1c825ebddf08d7e6ce16a47719a13d1b94751d37 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Fri, 28 Aug 2020 14:26:57 +0200 Subject: [PATCH 137/384] csg2d - better check for spline overlapping --- libsrc/geom2d/csg2d.cpp | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/libsrc/geom2d/csg2d.cpp b/libsrc/geom2d/csg2d.cpp index 31f707e5..d3e92c57 100644 --- a/libsrc/geom2d/csg2d.cpp +++ b/libsrc/geom2d/csg2d.cpp @@ -332,26 +332,38 @@ bool IsOverlapping( Spline p, Spline s, double & alpha, double & beta, Intersect double lam0 = -1e3*EPSILON; double lam1 = -1e3*EPSILON; + double lam2 = -1e3*EPSILON; + double lam3 = -1e3*EPSILON; alpha=-1e8; beta=-1e8; + double alpha_mid=-1e8; + double beta_mid=-1e8; // Check if s.p0 lies on p and vice versa, also check if tangents are in same direction (TODO: TEST) // If so, assume overlapping splines // TODO: Better checks! False positives could happen here! IntersectSplineSegment1( p, s.StartPI(), p_mid, lam0, alpha ); IntersectSplineSegment1( s, p.StartPI(), s_mid, lam1, beta ); + + // Also check if midpoints lie on other spline + IntersectSplineSegment1( p, s.GetPoint(0.5), p_mid, lam2, alpha_mid ); + IntersectSplineSegment1( s, p.GetPoint(0.5), s_mid, lam3, beta_mid ); + auto tang0 = s.GetTangent(0.); auto tang1 = p.GetTangent(alpha); double err = tang0*tang1; err*=err; err *= 1.0/(tang0.Length2()*tang1.Length2()); - if(fabs(lam0) < 1e3*EPSILON && fabs(lam1) < 1e3*EPSILON /*&& err < EPSILON*/) - { - type = ClassifyOverlappingIntersection( alpha, beta ); - return true; - } - return false; + double constexpr eps = 1e3*EPSILON; + if(fabs(lam0)>eps) return false; + if(fabs(lam1)>eps) return false; + if(fabs(lam2)>eps) return false; + if(fabs(lam3)>eps) return false; + if(fabs(1.0-err)>eps) return false; + + type = ClassifyOverlappingIntersection( alpha, beta ); + return true; } bool IsInsideTrig( const array,3> & t, Point<2> r ) From 956b06f90786fca6a53f453fdb30e06765360ae7 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Fri, 28 Aug 2020 17:26:43 +0200 Subject: [PATCH 138/384] csg2d - fix inside tests --- libsrc/geom2d/csg2d.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/libsrc/geom2d/csg2d.cpp b/libsrc/geom2d/csg2d.cpp index d3e92c57..5f004349 100644 --- a/libsrc/geom2d/csg2d.cpp +++ b/libsrc/geom2d/csg2d.cpp @@ -24,7 +24,7 @@ void ComputeWeight( Spline & s, Point<2> p ) double A = (p[1]-a[1])*(b[0]-p[0]) - (p[0]-a[0])*(b[1]-p[1]); double B = (p[1]-c[1])*(b[0]-p[0]) - (p[0]-c[0])*(b[1]-p[1]); double det = sqrt(-A*B); - double tt = (B-det)/(A+det); + double tt = fabs(A+det) fabs(v[1]) ? 0 : 1; double weight = fabs(tt*(p[dim]-a[dim])/v[dim] + 1.0/tt*(p[dim]-c[dim])/v[dim]); @@ -1485,12 +1485,12 @@ bool Solid2d :: IsLeftInside( const Vertex & p0 ) { auto s = *p0.spline; auto v = s.GetTangent(0.5); - auto n = Vec<2>{v[1], -v[0]}; + auto n = Vec<2>{-v[1], v[0]}; auto q = s.GetPoint(0.5) + 1e-6*n; return IsInside(q); } auto v = p1-p0; - auto n = Vec<2>{v[1], -v[0]}; + auto n = Vec<2>{-v[1], v[0]}; auto q = p0 + 0.5*v + 1e-6*n; return IsInside(q); @@ -1503,13 +1503,13 @@ bool Solid2d :: IsRightInside( const Vertex & p0 ) { auto s = *p0.spline; auto v = s.GetTangent(0.5); - auto n = Vec<2>{-v[1], v[0]}; + auto n = Vec<2>{v[1], -v[0]}; auto q = s.GetPoint(0.5) + 1e-6*n; return IsInside(q); } auto v = p1-p0; - auto n = Vec<2>{-v[1], v[0]}; + auto n = Vec<2>{v[1], -v[0]}; auto q = p0 + 0.5*v + 1e-6*n; return IsInside(q); } @@ -1643,7 +1643,7 @@ shared_ptr CSG2d :: GenerateSplineGeometry() if(li!=ri) { - if(s.IsLeftInside(p0) == flip) + if(s.IsLeftInside(p0) != flip) ls.left = dom; else ls.right = dom; From f2b9251032360f9f1fc2b8e5250b6f7ae82cbb55 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Fri, 28 Aug 2020 17:28:35 +0200 Subject: [PATCH 139/384] csg2d - tests --- tests/pytest/test_csg2d.py | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 tests/pytest/test_csg2d.py diff --git a/tests/pytest/test_csg2d.py b/tests/pytest/test_csg2d.py new file mode 100644 index 00000000..3afc29ef --- /dev/null +++ b/tests/pytest/test_csg2d.py @@ -0,0 +1,33 @@ +from netgen.geom2d import * +import pytest +import math +from pytest import approx + +def test_two_circles(): + c1 = Circle(center=(0,0), radius=1) + c2 = c1.Rotate(deg=45) + s = c1*c2 + geo = CSG2d() + geo.Add(s) + m = geo.GenerateMesh() + assert m.ne > 0 + + ngs = pytest.importorskip("ngsolve") + mesh = ngs.Mesh(m) + mesh.Curve(5) + assert ngs.Integrate(1.0, mesh) == approx(math.pi) + +def test_two_edge(): + s = Solid2d( [(-1,0), cp(0,1), (1,0), cp(0,2)] ) + geo = CSG2d() + geo.Add(s) + m = geo.GenerateMesh() + assert m.ne > 0 + + ngs = pytest.importorskip("ngsolve") + g = geo.GenerateSplineGeometry() + ngs.Draw(g) + +if __name__ == "__main__": + test_two_circles() + test_two_edge() From 2a7d6bb55edc11353c967930175380389359092b Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Fri, 28 Aug 2020 18:35:35 +0200 Subject: [PATCH 140/384] csg2d - fix overlap detection, test --- libsrc/geom2d/csg2d.cpp | 21 ++++++++++++--------- tests/pytest/test_csg2d.py | 31 +++++++++++++++++++++++++++++-- 2 files changed, 41 insertions(+), 11 deletions(-) diff --git a/libsrc/geom2d/csg2d.cpp b/libsrc/geom2d/csg2d.cpp index 5f004349..c3e0c950 100644 --- a/libsrc/geom2d/csg2d.cpp +++ b/libsrc/geom2d/csg2d.cpp @@ -268,7 +268,7 @@ IntersectionType IntersectSplineSegment( const Spline & s, const Point<2> & r0, return ClassifyNonOverlappingIntersection(alpha, beta); } -IntersectionType IntersectSplineSegment1( const Spline & s, const Point<2> & r0, const Point<2> & r1, double& alpha, double& beta ) +IntersectionType IntersectSplineSegment1( const Spline & s, const Point<2> & r0, const Point<2> & r1, double& alpha, double& beta, bool first=false) { Point<2> p0 = s.StartPI(); Point<2> p1 = s.TangentPoint(); @@ -310,11 +310,14 @@ IntersectionType IntersectSplineSegment1( const Spline & s, const Point<2> & r0, } int choice = 0; - if(vtype[0]==NO_INTERSECTION && vtype[1]!=NO_INTERSECTION) - choice = 1; + if(!first) + { + if(vtype[0]==NO_INTERSECTION && vtype[1]!=NO_INTERSECTION) + choice = 1; - if(valpha[0] < alpha+EPSILON) - choice = 1; + if(valpha[0] < alpha+EPSILON) + choice = 1; + } if(valpha[choice] < alpha+EPSILON) return NO_INTERSECTION; @@ -342,12 +345,12 @@ bool IsOverlapping( Spline p, Spline s, double & alpha, double & beta, Intersect // Check if s.p0 lies on p and vice versa, also check if tangents are in same direction (TODO: TEST) // If so, assume overlapping splines // TODO: Better checks! False positives could happen here! - IntersectSplineSegment1( p, s.StartPI(), p_mid, lam0, alpha ); - IntersectSplineSegment1( s, p.StartPI(), s_mid, lam1, beta ); + IntersectSplineSegment1( p, s.StartPI(), p_mid, lam0, alpha, true ); + IntersectSplineSegment1( s, p.StartPI(), s_mid, lam1, beta, true ); // Also check if midpoints lie on other spline - IntersectSplineSegment1( p, s.GetPoint(0.5), p_mid, lam2, alpha_mid ); - IntersectSplineSegment1( s, p.GetPoint(0.5), s_mid, lam3, beta_mid ); + IntersectSplineSegment1( p, s.GetPoint(0.5), p_mid, lam2, alpha_mid, true ); + IntersectSplineSegment1( s, p.GetPoint(0.5), s_mid, lam3, beta_mid, true ); auto tang0 = s.GetTangent(0.); auto tang1 = p.GetTangent(alpha); diff --git a/tests/pytest/test_csg2d.py b/tests/pytest/test_csg2d.py index 3afc29ef..d962085c 100644 --- a/tests/pytest/test_csg2d.py +++ b/tests/pytest/test_csg2d.py @@ -10,24 +10,51 @@ def test_two_circles(): geo = CSG2d() geo.Add(s) m = geo.GenerateMesh() - assert m.ne > 0 + assert len(m.Elements2D()) > 0 ngs = pytest.importorskip("ngsolve") mesh = ngs.Mesh(m) mesh.Curve(5) assert ngs.Integrate(1.0, mesh) == approx(math.pi) + ngs.Draw(mesh) def test_two_edge(): s = Solid2d( [(-1,0), cp(0,1), (1,0), cp(0,2)] ) geo = CSG2d() geo.Add(s) m = geo.GenerateMesh() - assert m.ne > 0 + assert len(m.Elements2D()) > 0 ngs = pytest.importorskip("ngsolve") g = geo.GenerateSplineGeometry() ngs.Draw(g) + mesh = ngs.Mesh(m) + mesh.Curve(5) + ngs.Draw(mesh) + +def test_trig_and_circle(): + g = CSG2d() + + trig = Solid2d( [(0,0), (1,1), (-1,1) ] ).BC("diamond") + circle = Circle( center=(0,0.101), radius=0.1).BC("circle") # TODO: Failing with center=(0,0.1) + + d = trig-circle + g.Add(d) + g.Add(circle) + + m = g.GenerateMesh(maxh=0.1) + assert len(m.Elements2D()) > 0 + + ngs = pytest.importorskip("ngsolve") + geo = g.GenerateSplineGeometry() + ngs.Draw(geo) + + mesh = ngs.Mesh(m) + mesh.Curve(3) + ngs.Draw(mesh) + if __name__ == "__main__": test_two_circles() test_two_edge() + test_trig_and_circle() From fcee13be59490fc570bed1e06acf27cdb03b37f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20Sch=C3=B6berl?= Date: Fri, 28 Aug 2020 21:28:18 +0200 Subject: [PATCH 141/384] modernize paralleltop --- libsrc/meshing/curvedelems.cpp | 219 ++++++++++++++------------------- libsrc/meshing/meshtype.hpp | 16 ++- libsrc/meshing/paralleltop.cpp | 70 +++++++++-- libsrc/meshing/paralleltop.hpp | 5 +- 4 files changed, 167 insertions(+), 143 deletions(-) diff --git a/libsrc/meshing/curvedelems.cpp b/libsrc/meshing/curvedelems.cpp index 7ea1086b..43628d3e 100644 --- a/libsrc/meshing/curvedelems.cpp +++ b/libsrc/meshing/curvedelems.cpp @@ -560,21 +560,13 @@ namespace netgen ishighorder = 0; order = 1; - // MPI_Comm curve_comm; - const auto & curve_comm = mesh.GetCommunicator(); + auto comm = mesh.GetCommunicator(); #ifdef PARALLEL enum { MPI_TAG_CURVE = MPI_TAG_MESH+20 }; - const ParallelMeshTopology & partop = mesh.GetParallelTopology (); - // MPI_Comm_dup (mesh.GetCommunicator(), &curve_comm); - NgArray procs; -#else - // curve_comm = mesh.GetCommunicator(); #endif - int id = curve_comm.Rank(); - int ntasks = curve_comm.Size(); - - bool working = (ntasks == 1) || (id > 0); + int ntasks = comm.Size(); + bool working = (ntasks == 1) || (comm.Rank() > 0); if (working) order = aorder; @@ -653,38 +645,26 @@ namespace netgen if (ntasks > 1 && working) { for (int e = 0; e < edgeorder.Size(); e++) - { - partop.GetDistantEdgeNums (e+1, procs); - for (int j = 0; j < procs.Size(); j++) - send_orders.Add (procs[j], edgeorder[e]); - } + for (int proc : partop.GetDistantEdgeNums(e)) + send_orders.Add (proc, edgeorder[e]); for (int f = 0; f < faceorder.Size(); f++) - { - partop.GetDistantFaceNums (f+1, procs); - for (int j = 0; j < procs.Size(); j++) - send_orders.Add (procs[j], faceorder[f]); - } + for (int proc : partop.GetDistantFaceNums(f)) + send_orders.Add (proc, faceorder[f]); } if (ntasks > 1) - MyMPI_ExchangeTable (send_orders, recv_orders, MPI_TAG_CURVE, curve_comm); + MyMPI_ExchangeTable (send_orders, recv_orders, MPI_TAG_CURVE, comm); if (ntasks > 1 && working) { NgArray cnt(ntasks); cnt = 0; for (int e = 0; e < edgeorder.Size(); e++) - { - partop.GetDistantEdgeNums (e+1, procs); - for (int j = 0; j < procs.Size(); j++) - edgeorder[e] = max(edgeorder[e], recv_orders[procs[j]][cnt[procs[j]]++]); - } + for (auto proc : partop.GetDistantEdgeNums(e)) + edgeorder[e] = max(edgeorder[e], recv_orders[proc][cnt[proc]++]); for (int f = 0; f < faceorder.Size(); f++) - { - partop.GetDistantFaceNums (f+1, procs); - for (int j = 0; j < procs.Size(); j++) - faceorder[f] = max(faceorder[f], recv_orders[procs[j]][cnt[procs[j]]++]); - } + for (auto proc : partop.GetDistantFaceNums(f)) + faceorder[f] = max(faceorder[f], recv_orders[proc][cnt[proc]++]); } #endif @@ -771,48 +751,40 @@ namespace netgen TABLE senddata(ntasks), recvdata(ntasks); if (working) for (int e = 0; e < nedges; e++) - { - partop.GetDistantEdgeNums (e+1, procs); - for (int j = 0; j < procs.Size(); j++) - { - senddata.Add (procs[j], surfnr[e]); - if (surfnr[e] != -1) - { - senddata.Add (procs[j], gi0[e].trignum); - senddata.Add (procs[j], gi0[e].u); - senddata.Add (procs[j], gi0[e].v); - senddata.Add (procs[j], gi1[e].trignum); - senddata.Add (procs[j], gi1[e].u); - senddata.Add (procs[j], gi1[e].v); - } - } - } - - MyMPI_ExchangeTable (senddata, recvdata, MPI_TAG_CURVE, curve_comm); + for (int proc : partop.GetDistantEdgeNums(e)) + { + senddata.Add (proc, surfnr[e]); + if (surfnr[e] != -1) + { + senddata.Add (proc, gi0[e].trignum); + senddata.Add (proc, gi0[e].u); + senddata.Add (proc, gi0[e].v); + senddata.Add (proc, gi1[e].trignum); + senddata.Add (proc, gi1[e].u); + senddata.Add (proc, gi1[e].v); + } + } + MyMPI_ExchangeTable (senddata, recvdata, MPI_TAG_CURVE, comm); NgArray cnt(ntasks); cnt = 0; if (working) for (int e = 0; e < nedges; e++) - { - partop.GetDistantEdgeNums (e+1, procs); - for (int j = 0; j < procs.Size(); j++) - { - int surfnr1 = recvdata[procs[j]][cnt[procs[j]]++]; - if (surfnr1 != -1) - { - surfnr[e] = surfnr1; - gi0[e].trignum = int (recvdata[procs[j]][cnt[procs[j]]++]); - gi0[e].u = recvdata[procs[j]][cnt[procs[j]]++]; - gi0[e].v = recvdata[procs[j]][cnt[procs[j]]++]; - gi1[e].trignum = int (recvdata[procs[j]][cnt[procs[j]]++]); - gi1[e].u = recvdata[procs[j]][cnt[procs[j]]++]; - gi1[e].v = recvdata[procs[j]][cnt[procs[j]]++]; - } - } - } - + for (int proc : partop.GetDistantEdgeNums(e)) + { + int surfnr1 = recvdata[proc][cnt[proc]++]; + if (surfnr1 != -1) + { + surfnr[e] = surfnr1; + gi0[e].trignum = int (recvdata[proc][cnt[proc]++]); + gi0[e].u = recvdata[proc][cnt[proc]++]; + gi0[e].v = recvdata[proc][cnt[proc]++]; + gi1[e].trignum = int (recvdata[proc][cnt[proc]++]); + gi1[e].u = recvdata[proc][cnt[proc]++]; + gi1[e].v = recvdata[proc][cnt[proc]++]; + } + } } #endif @@ -974,59 +946,53 @@ namespace netgen TABLE senddata(ntasks), recvdata(ntasks); if (working) for (int e = 0; e < nedges; e++) - { - partop.GetDistantEdgeNums (e+1, procs); - for (int j = 0; j < procs.Size(); j++) - { - senddata.Add (procs[j], use_edge[e]); - if (use_edge[e]) - { - senddata.Add (procs[j], edge_surfnr1[e]); - senddata.Add (procs[j], edge_surfnr2[e]); - senddata.Add (procs[j], edge_gi0[e].edgenr); - senddata.Add (procs[j], edge_gi0[e].body); - senddata.Add (procs[j], edge_gi0[e].dist); - senddata.Add (procs[j], edge_gi0[e].u); - senddata.Add (procs[j], edge_gi0[e].v); - senddata.Add (procs[j], edge_gi1[e].edgenr); - senddata.Add (procs[j], edge_gi1[e].body); - senddata.Add (procs[j], edge_gi1[e].dist); - senddata.Add (procs[j], edge_gi1[e].u); - senddata.Add (procs[j], edge_gi1[e].v); - senddata.Add (procs[j], swap_edge[e]); - } - } - } - MyMPI_ExchangeTable (senddata, recvdata, MPI_TAG_CURVE, curve_comm); + for (int proc : partop.GetDistantEdgeNums(e)) + { + senddata.Add (proc, use_edge[e]); + if (use_edge[e]) + { + senddata.Add (proc, edge_surfnr1[e]); + senddata.Add (proc, edge_surfnr2[e]); + senddata.Add (proc, edge_gi0[e].edgenr); + senddata.Add (proc, edge_gi0[e].body); + senddata.Add (proc, edge_gi0[e].dist); + senddata.Add (proc, edge_gi0[e].u); + senddata.Add (proc, edge_gi0[e].v); + senddata.Add (proc, edge_gi1[e].edgenr); + senddata.Add (proc, edge_gi1[e].body); + senddata.Add (proc, edge_gi1[e].dist); + senddata.Add (proc, edge_gi1[e].u); + senddata.Add (proc, edge_gi1[e].v); + senddata.Add (proc, swap_edge[e]); + } + } + + MyMPI_ExchangeTable (senddata, recvdata, MPI_TAG_CURVE, comm); NgArray cnt(ntasks); cnt = 0; if (working) for (int e = 0; e < edge_surfnr1.Size(); e++) - { - partop.GetDistantEdgeNums (e+1, procs); - for (int j = 0; j < procs.Size(); j++) - { - int get_edge = int(recvdata[procs[j]][cnt[procs[j]]++]); - if (get_edge) - { - use_edge[e] = 1; - edge_surfnr1[e] = int (recvdata[procs[j]][cnt[procs[j]]++]); - edge_surfnr2[e] = int (recvdata[procs[j]][cnt[procs[j]]++]); - edge_gi0[e].edgenr = int (recvdata[procs[j]][cnt[procs[j]]++]); - edge_gi0[e].body = int (recvdata[procs[j]][cnt[procs[j]]++]); - edge_gi0[e].dist = recvdata[procs[j]][cnt[procs[j]]++]; - edge_gi0[e].u = recvdata[procs[j]][cnt[procs[j]]++]; - edge_gi0[e].v = recvdata[procs[j]][cnt[procs[j]]++]; - edge_gi1[e].edgenr = int (recvdata[procs[j]][cnt[procs[j]]++]); - edge_gi1[e].body = int (recvdata[procs[j]][cnt[procs[j]]++]); - edge_gi1[e].dist = recvdata[procs[j]][cnt[procs[j]]++]; - edge_gi1[e].u = recvdata[procs[j]][cnt[procs[j]]++]; - edge_gi1[e].v = recvdata[procs[j]][cnt[procs[j]]++]; - swap_edge[e] = recvdata[procs[j]][cnt[procs[j]]++]; - } - } - } - + for (int proc : partop.GetDistantEdgeNums(e)) + { + int get_edge = int(recvdata[proc][cnt[proc]++]); + if (get_edge) + { + use_edge[e] = 1; + edge_surfnr1[e] = int (recvdata[proc][cnt[proc]++]); + edge_surfnr2[e] = int (recvdata[proc][cnt[proc]++]); + edge_gi0[e].edgenr = int (recvdata[proc][cnt[proc]++]); + edge_gi0[e].body = int (recvdata[proc][cnt[proc]++]); + edge_gi0[e].dist = recvdata[proc][cnt[proc]++]; + edge_gi0[e].u = recvdata[proc][cnt[proc]++]; + edge_gi0[e].v = recvdata[proc][cnt[proc]++]; + edge_gi1[e].edgenr = int (recvdata[proc][cnt[proc]++]); + edge_gi1[e].body = int (recvdata[proc][cnt[proc]++]); + edge_gi1[e].dist = recvdata[proc][cnt[proc]++]; + edge_gi1[e].u = recvdata[proc][cnt[proc]++]; + edge_gi1[e].v = recvdata[proc][cnt[proc]++]; + swap_edge[e] = recvdata[proc][cnt[proc]++]; + } + } } #endif @@ -1182,26 +1148,20 @@ namespace netgen if (ntasks > 1 && working) { for (int f = 0; f < nfaces; f++) - { - partop.GetDistantFaceNums (f+1, procs); - for (int j = 0; j < procs.Size(); j++) - send_surfnr.Add (procs[j], surfnr[f]); - } + for (int proc : partop.GetDistantFaceNums(f)) + send_surfnr.Add (proc, surfnr[f]); } if (ntasks > 1) - MyMPI_ExchangeTable (send_surfnr, recv_surfnr, MPI_TAG_CURVE, curve_comm); + MyMPI_ExchangeTable (send_surfnr, recv_surfnr, MPI_TAG_CURVE, comm); if (ntasks > 1 && working) { NgArray cnt(ntasks); cnt = 0; for (int f = 0; f < nfaces; f++) - { - partop.GetDistantFaceNums (f+1, procs); - for (int j = 0; j < procs.Size(); j++) - surfnr[f] = max(surfnr[f], recv_surfnr[procs[j]][cnt[procs[j]]++]); - } + for (int proc : partop.GetDistantFaceNums(f)) + surfnr[f] = max(surfnr[f], recv_surfnr[proc][cnt[proc]++]); } #endif @@ -1386,8 +1346,7 @@ namespace netgen #ifdef PARALLEL - curve_comm.Barrier(); - // MPI_Comm_free (&curve_comm); + comm.Barrier(); #endif } diff --git a/libsrc/meshing/meshtype.hpp b/libsrc/meshing/meshtype.hpp index 30c269e6..be4482d6 100644 --- a/libsrc/meshing/meshtype.hpp +++ b/libsrc/meshing/meshtype.hpp @@ -220,10 +220,22 @@ namespace netgen PointIndices (PointIndex i1, PointIndex i2) : INDEX_2(i1,i2) { ; } PointIndex operator[] (int i) const { return PointIndex(INDEX_2::operator[](i)); } PointIndex & operator[] (int i) { return reinterpret_cast(INDEX_2::operator[](i)); } - static PointIndices Sort(PointIndex i1, PointIndex i2) { return INDEX_2::Sort(i1, i2); } + static PointIndices Sort(PointIndex i1, PointIndex i2) { return INDEX_2::Sort(i1, i2); } + template + PointIndex get() const { return PointIndex(INDEX_2::operator[](J)); } }; - +} +namespace std +{ + // structured binding support + template + struct tuple_size> : std::integral_constant {}; + template struct tuple_element> { using type = netgen::PointIndex; }; +} + +namespace netgen +{ class ElementIndex { diff --git a/libsrc/meshing/paralleltop.cpp b/libsrc/meshing/paralleltop.cpp index f2337b18..418913e3 100644 --- a/libsrc/meshing/paralleltop.cpp +++ b/libsrc/meshing/paralleltop.cpp @@ -15,6 +15,7 @@ namespace ngcore if (v > max) max = v; return max; } + /* template auto Max (FlatArray array, TB initial) -> T @@ -546,11 +547,18 @@ namespace netgen { PointIndex v1 = mesh.mlbetweennodes[pi][0]; PointIndex v2 = mesh.mlbetweennodes[pi][1]; + /* if (mesh.mlbetweennodes[pi][0] != PointIndex::BASE-1) - // for (int dest = 1; dest < ntasks; dest++) for (int dest : GetDistantPNums(v1-PointIndex::BASE)) if (IsExchangeVert (dest, v1) && IsExchangeVert (dest, v2)) cnt_send[dest-1]++; + */ + auto procs1 = GetDistantProcs(v1); + auto procs2 = GetDistantProcs(v2); + if (mesh.mlbetweennodes[pi][0] != PointIndex::BASE-1) + for (int p : procs1) + if (procs2.Contains(p)) + cnt_send[p-1]++; } TABLE dest2pair(cnt_send); @@ -559,22 +567,39 @@ namespace netgen { PointIndex v1 = mesh.mlbetweennodes[pi][0]; PointIndex v2 = mesh.mlbetweennodes[pi][1]; + auto procs1 = GetDistantProcs(v1); + auto procs2 = GetDistantProcs(v2); + /* if (mesh.mlbetweennodes[pi][0] != PointIndex::BASE-1) for (int dest : GetDistantPNums(v1-PointIndex::BASE)) if (IsExchangeVert (dest, v1) && IsExchangeVert (dest, v2)) dest2pair.Add (dest-1, pi); + */ + if (mesh.mlbetweennodes[pi][0] != PointIndex::BASE-1) + for (int p : procs1) + if (procs2.Contains(p)) + dest2pair.Add (p-1, pi); } cnt_send = 0; int v1, v2; for (PointIndex pi = PointIndex::BASE; pi < newnv+PointIndex::BASE; pi++) { - PointIndex v1 = mesh.mlbetweennodes[pi][0]; - PointIndex v2 = mesh.mlbetweennodes[pi][1]; + // PointIndex v1 = mesh.mlbetweennodes[pi][0]; + // PointIndex v2 = mesh.mlbetweennodes[pi][1]; + auto [v1,v2] = mesh.mlbetweennodes[pi]; + auto procs1 = GetDistantProcs(v1); + auto procs2 = GetDistantProcs(v2); + /* if (mesh.mlbetweennodes[pi][0] != PointIndex::BASE-1) for (int dest : GetDistantPNums(v1-PointIndex::BASE)) if (IsExchangeVert(dest, v2)) cnt_send[dest-1]+=2; + */ + if (mesh.mlbetweennodes[pi][0] != PointIndex::BASE-1) + for (int p : procs1) + if (procs2.Contains(p)) + cnt_send[p-1]+=2; } TABLE send_verts(cnt_send); @@ -598,8 +623,11 @@ namespace netgen { PointIndex v1 = mesh.mlbetweennodes[pi][0]; PointIndex v2 = mesh.mlbetweennodes[pi][1]; + auto procs1 = GetDistantProcs(v1); + auto procs2 = GetDistantProcs(v2); if (mesh.mlbetweennodes[pi][0] != PointIndex::BASE-1) - if (IsExchangeVert (dest, v1) && IsExchangeVert (dest, v2)) + // if (IsExchangeVert (dest, v1) && IsExchangeVert (dest, v2)) + if (procs1.Contains(dest) && procs2.Contains(dest)) { send_verts.Add (dest-1, loc2exchange[v1]); send_verts.Add (dest-1, loc2exchange[v2]); @@ -634,7 +662,8 @@ namespace netgen { INDEX_2 re(recvarray[ii], recvarray[ii+1]); INDEX_2 es(loc2exchange[v1], loc2exchange[v2]); - if (es == re && !IsExchangeVert(dest, pi)) + // if (es == re && !IsExchangeVert(dest, pi)) + if (es == re && !GetDistantProcs(pi).Contains(dest)) { SetDistantPNum(dest, pi); changed = true; @@ -870,7 +899,7 @@ namespace netgen #endif - NgArray sendarray, recvarray; + // NgArray sendarray, recvarray; // cout << "UpdateCoarseGrid - edges" << endl; // static int timerv = NgProfiler::CreateTimer ("UpdateCoarseGrid - ex vertices"); @@ -900,9 +929,15 @@ namespace netgen for (int edge = 1; edge <= ned; edge++) { topology.GetEdgeVertices (edge, v1, v2); + /* for (int dest = 1; dest < ntasks; dest++) - if (IsExchangeVert (dest, v1) && IsExchangeVert (dest, v2)) + // if (IsExchangeVert (dest, v1) && IsExchangeVert (dest, v2)) + if (GetDistantProcs(v1).Contains(dest) && GetDistantProcs(v2).Contains(dest)) cnt_send[dest-1]+=1; + */ + for (auto p : GetDistantProcs(v1)) + if (GetDistantProcs(v2).Contains(p)) + cnt_send[p-1]+=1; } TABLE dest2edge(cnt_send); @@ -913,7 +948,8 @@ namespace netgen { topology.GetEdgeVertices (edge, v1, v2); for (int dest = 1; dest < ntasks; dest++) - if (IsExchangeVert (dest, v1) && IsExchangeVert (dest, v2)) + // if (IsExchangeVert (dest, v1) && IsExchangeVert (dest, v2)) + if (GetDistantProcs(v1).Contains(dest) && GetDistantProcs(v2).Contains(dest)) dest2edge.Add (dest-1, edge); } @@ -929,7 +965,8 @@ namespace netgen for (int edge : dest2edge[dest-1]) { topology.GetEdgeVertices (edge, v1, v2); - if (IsExchangeVert (dest, v1) && IsExchangeVert (dest, v2)) + // if (IsExchangeVert (dest, v1) && IsExchangeVert (dest, v2)) + if (GetDistantProcs(v1).Contains(dest) && GetDistantProcs(v2).Contains(dest)) { send_edges.Add (dest-1, loc2exchange[v1]); send_edges.Add (dest-1, loc2exchange[v2]); @@ -981,9 +1018,14 @@ namespace netgen topology.GetFaceVertices (face, verts); for (int dest = 1; dest < ntasks; dest++) if (dest != id) + /* if (IsExchangeVert (dest, verts[0]) && IsExchangeVert (dest, verts[1]) && IsExchangeVert (dest, verts[2])) + */ + if (GetDistantProcs (verts[0]).Contains(dest) && + GetDistantProcs (verts[1]).Contains(dest) && + GetDistantProcs (verts[2]).Contains(dest)) cnt_send[dest-1]++; } @@ -993,9 +1035,14 @@ namespace netgen topology.GetFaceVertices (face, verts); for (int dest = 1; dest < ntasks; dest++) if (dest != id) + /* if (IsExchangeVert (dest, verts[0]) && IsExchangeVert (dest, verts[1]) && IsExchangeVert (dest, verts[2])) + */ + if (GetDistantProcs (verts[0]).Contains(dest) && + GetDistantProcs (verts[1]).Contains(dest) && + GetDistantProcs (verts[2]).Contains(dest)) dest2face.Add(dest-1, face); } @@ -1015,9 +1062,14 @@ namespace netgen for (int face : dest2face[dest-1]) { topology.GetFaceVertices (face, verts); + /* if (IsExchangeVert (dest, verts[0]) && IsExchangeVert (dest, verts[1]) && IsExchangeVert (dest, verts[2])) + */ + if (GetDistantProcs (verts[0]).Contains(dest) && + GetDistantProcs (verts[1]).Contains(dest) && + GetDistantProcs (verts[2]).Contains(dest)) { send_faces.Add (dest-1, loc2exchange[verts[0]]); send_faces.Add (dest-1, loc2exchange[verts[1]]); diff --git a/libsrc/meshing/paralleltop.hpp b/libsrc/meshing/paralleltop.hpp index 8589801b..26f3f143 100644 --- a/libsrc/meshing/paralleltop.hpp +++ b/libsrc/meshing/paralleltop.hpp @@ -117,17 +117,18 @@ namespace netgen distedgenums = loc2distedge[locedgenum-1]; } + [[deprecated("Use GetDistantProcs(..)!")]] FlatArray GetDistantPNums (int locnum) const { return loc2distvert[locnum]; } FlatArray GetDistantFaceNums (int locnum) const { return loc2distface[locnum]; } FlatArray GetDistantEdgeNums (int locnum) const { return loc2distedge[locnum]; } - [[deprecated("Use GetDistantPNums(..).Contains instead!")]] + FlatArray GetDistantProcs (PointIndex pi) const { return loc2distvert[pi-PointIndex::BASE]; } + [[deprecated("Use GetDistantProcs(..).Contains instead!")]] bool IsExchangeVert (int dest, int vnum) const { return loc2distvert[vnum-1].Contains (dest); } }; - } From f8dd4be8d683733f909cfe9d6aef217ace4c2a79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20Sch=C3=B6berl?= Date: Sat, 29 Aug 2020 09:36:46 +0200 Subject: [PATCH 142/384] modernize ParallelTopology --- libsrc/core/table.cpp | 8 +- libsrc/core/table.hpp | 138 ++++++++++++++++++++++++++------- libsrc/meshing/paralleltop.cpp | 89 +++++++++++---------- libsrc/meshing/paralleltop.hpp | 4 + 4 files changed, 164 insertions(+), 75 deletions(-) diff --git a/libsrc/core/table.cpp b/libsrc/core/table.cpp index 62f544d0..ad69694b 100644 --- a/libsrc/core/table.cpp +++ b/libsrc/core/table.cpp @@ -54,7 +54,7 @@ namespace ngcore NGCORE_API size_t * TablePrefixSum64 (FlatArray entrysize) { return TablePrefixSum2 (entrysize); } - + /* BaseDynamicTable :: BaseDynamicTable (int size) : data(size) { @@ -88,7 +88,6 @@ namespace ngcore } } - BaseDynamicTable :: ~BaseDynamicTable () { if (oneblock) @@ -112,7 +111,7 @@ namespace ngcore } } - void BaseDynamicTable :: IncSize (int i, int elsize) + void BaseDynamicTable :: IncSize (IndexType i, int elsize) { if (i < 0 || i >= data.Size()) { @@ -135,7 +134,7 @@ namespace ngcore line.size++; } - void BaseDynamicTable :: DecSize (int i) + void BaseDynamicTable :: DecSize (IndexType i) { if (i < 0 || i >= data.Size()) { @@ -153,6 +152,7 @@ namespace ngcore line.size--; } + */ void FilteredTableCreator::Add (size_t blocknr, int data) { diff --git a/libsrc/core/table.hpp b/libsrc/core/table.hpp index 8a565a44..a1033973 100644 --- a/libsrc/core/table.hpp +++ b/libsrc/core/table.hpp @@ -349,11 +349,13 @@ public: }; - /// Base class to generic DynamicTable. +/// Base class to generic DynamicTable. +template class BaseDynamicTable { protected: - + static constexpr IndexType BASE = IndexBASE(); + /// struct linestruct { @@ -366,24 +368,106 @@ public: }; /// - Array data; + Array data; /// char * oneblock; public: /// - NGCORE_API BaseDynamicTable (int size); + BaseDynamicTable (int size) + : data(size) + { + for (auto & d : data) + { + d.maxsize = 0; + d.size = 0; + d.col = nullptr; + } + oneblock = nullptr; + } + /// - NGCORE_API BaseDynamicTable (const Array & entrysizes, int elemsize); + BaseDynamicTable (const Array & entrysizes, int elemsize) + : data(entrysizes.Size()) + { + int cnt = 0; + int n = entrysizes.Size(); + + for (auto es : entrysizes) + cnt += es; + oneblock = new char[elemsize * cnt]; + + cnt = 0; + for (auto i : Range(data)) + { + data[i].maxsize = entrysizes[i]; + data[i].size = 0; + data[i].col = &oneblock[elemsize * cnt]; + cnt += entrysizes[i]; + } + } /// - NGCORE_API ~BaseDynamicTable (); + ~BaseDynamicTable () + { + if (oneblock) + delete [] oneblock; + else + for (auto & d : data) + delete [] static_cast (d.col); + } /// Changes Size of table to size, deletes data - NGCORE_API void SetSize (int size); + void SetSize (int size) + { + for (auto & d : data) + delete [] static_cast (d.col); + + data.SetSize(size); + for (auto & d : data) + { + d.maxsize = 0; + d.size = 0; + d.col = NULL; + } + } + /// - NGCORE_API void IncSize (int i, int elsize); + void IncSize (IndexType i, int elsize) + { + NETGEN_CHECK_RANGE(i,BASE,data.Size()+BASE); + + linestruct & line = data[i]; + + if (line.size == line.maxsize) + { + void * p = new char [(2*line.maxsize+5) * elsize]; + + memcpy (p, line.col, line.maxsize * elsize); + delete [] static_cast (line.col); + line.col = p; + line.maxsize = 2*line.maxsize+5; + } + + line.size++; + } - NGCORE_API void DecSize (int i); + void DecSize (IndexType i) + { + NETGEN_CHECK_RANGE(i,BASE,data.Size()+BASE); + /* + if (i < 0 || i >= data.Size()) + { + std::cerr << "BaseDynamicTable::Dec: Out of range" << std::endl; + return; + } + */ + linestruct & line = data[i]; + + if (line.size == 0) + throw Exception ("BaseDynamicTable::Dec: EntrySize < 0"); + + line.size--; + } }; @@ -394,17 +478,19 @@ public: A DynamicTable contains entries of variable size. Entry sizes can be increased dynamically. */ - template - class DynamicTable : public BaseDynamicTable +template +class DynamicTable : public BaseDynamicTable { + using BaseDynamicTable::data; + using BaseDynamicTable::oneblock; public: /// Creates table of size size DynamicTable (int size = 0) - : BaseDynamicTable (size) { ; } + : BaseDynamicTable (size) { } /// Creates table with a priori fixed entry sizes. - DynamicTable (const Array & entrysizes) - : BaseDynamicTable (entrysizes, sizeof(T)) { ; } + DynamicTable (const Array & entrysizes) + : BaseDynamicTable (entrysizes, sizeof(T)) { } DynamicTable & operator= (DynamicTable && tab2) { @@ -412,19 +498,19 @@ public: Swap (oneblock, tab2.oneblock); return *this; } - + /// Inserts element acont into row i. Does not test if already used. - void Add (int i, const T & acont) + void Add (IndexType i, const T & acont) { if (data[i].size == data[i].maxsize) - IncSize (i, sizeof (T)); + this->IncSize (i, sizeof (T)); else data[i].size++; static_cast (data[i].col) [data[i].size-1] = acont; } /// Inserts element acont into row i, iff not yet exists. - void AddUnique (int i, const T & cont) + void AddUnique (IndexType i, const T & cont) { int es = EntrySize (i); int * line = const_cast (GetLine (i)); @@ -436,25 +522,25 @@ public: /// Inserts element acont into row i. Does not test if already used. - void AddEmpty (int i) + void AddEmpty (IndexType i) { IncSize (i, sizeof (T)); } /** Set the nr-th element in the i-th row to acont. Does not check for overflow. */ - void Set (int i, int nr, const T & acont) + void Set (IndexType i, int nr, const T & acont) { static_cast (data[i].col)[nr] = acont; } /** Returns the nr-th element in the i-th row. Does not check for overflow. */ - const T & Get (int i, int nr) const + const T & Get (IndexType i, int nr) const { return static_cast (data[i].col)[nr]; } /** Returns pointer to the first element in row i. */ - const T * GetLine (int i) const + const T * GetLine (IndexType i) const { return static_cast (data[i].col); } @@ -463,15 +549,15 @@ public: { return data.Size(); } /// Returns size of the i-th row. - int EntrySize (int i) const + int EntrySize (IndexType i) const { return data[i].size; } /// - void DecEntrySize (int i) + void DecEntrySize (IndexType i) { DecSize(i); } /// Access entry i - FlatArray operator[] (int i) + FlatArray operator[] (IndexType i) { return FlatArray (data[i].size, static_cast (data[i].col)); } /* @@ -480,7 +566,7 @@ public: ConstFlatArray operator[] (int i) const { return FlatArray (data[i].size, static_cast (data[i].col)); } */ - FlatArray operator[] (int i) const + FlatArray operator[] (IndexType i) const { return FlatArray (data[i].size, static_cast (data[i].col)); } }; diff --git a/libsrc/meshing/paralleltop.cpp b/libsrc/meshing/paralleltop.cpp index 418913e3..c1b83abe 100644 --- a/libsrc/meshing/paralleltop.cpp +++ b/libsrc/meshing/paralleltop.cpp @@ -51,8 +51,8 @@ namespace netgen if ( mesh.GetCommunicator().Size() == 1 ) return; - int ned = mesh.GetTopology().GetNEdges(); - int nfa = mesh.GetTopology().GetNFaces(); + size_t ned = mesh.GetTopology().GetNEdges(); + size_t nfa = mesh.GetTopology().GetNFaces(); if (glob_edge.Size() != ned) { @@ -89,29 +89,30 @@ namespace netgen *testout << "enumerate globally, loc2distvert.size = " << loc2distvert.Size() << ", glob_vert.size = " << glob_vert.Size() << endl; - // *testout << "old glob_vert = " << endl << glob_vert << endl; if (rank == 0) nv = 0; - IntRange newvr(oldnv, nv); // new vertex range + // IntRange newvr(oldnv, nv); // new vertex range + auto new_pir = Range(PointIndex(oldnv+PointIndex::BASE), + PointIndex(nv+PointIndex::BASE)); glob_vert.SetSize (nv); - glob_vert.Range(newvr) = -1; + glob_vert.Range(oldnv, nv) = -1; int num_master_points = 0; - for (auto i : newvr) + for (auto pi : new_pir) { - auto dps = GetDistantPNums(i); + auto dps = GetDistantProcs(pi); // check sorted: for (int j = 0; j+1 < dps.Size(); j++) if (dps[j+1] < dps[j]) cout << "wrong sort" << endl; if (dps.Size() == 0 || dps[0] > comm.Rank()) - glob_vert[i] = num_master_points++; + L2G(pi) = num_master_points++; } - + *testout << "nummaster = " << num_master_points << endl; Array first_master_point(comm.Size()); @@ -120,7 +121,7 @@ namespace netgen if (comm.AllReduce (oldnv, MPI_SUM) == 0) max_oldv = PointIndex::BASE-1; - size_t num_glob_points = max_oldv+1; // PointIndex::BASE; + size_t num_glob_points = max_oldv+1; for (int i = 0; i < comm.Size(); i++) { int cur = first_master_point[i]; @@ -128,9 +129,9 @@ namespace netgen num_glob_points += cur; } - for (auto i : newvr) - if (glob_vert[i] != -1) - glob_vert[i] += first_master_point[comm.Rank()]; + for (auto pi : new_pir) + if (L2G(pi) != -1) + L2G(pi) += first_master_point[comm.Rank()]; // ScatterDofData (global_nums); @@ -139,12 +140,12 @@ namespace netgen nrecv = 0; /** Count send/recv size **/ - for (auto i : newvr) + for (auto pi : new_pir) { - auto dps = GetDistantPNums(i); + auto dps = GetDistantProcs(pi); if (!dps.Size()) continue; if (rank < dps[0]) - for(auto p:dps) + for (auto p : dps) nsend[p]++; else nrecv[dps[0]]++; @@ -155,14 +156,12 @@ namespace netgen /** Fill send_data **/ nsend = 0; - for (auto i : newvr) - { - auto dps = GetDistantPNums(i); - if (dps.Size() && rank < dps[0]) - for(auto p : dps) - send_data[p][nsend[p]++] = glob_vert[i]; - } - + for (auto pi : new_pir) + if (auto dps = GetDistantProcs(pi); dps.Size()) + if (rank < dps[0]) + for (auto p : dps) + send_data[p][nsend[p]++] = L2G(pi); + Array requests; for (int i = 0; i < comm.Size(); i++) { @@ -176,21 +175,23 @@ namespace netgen Array cnt(comm.Size()); cnt = 0; - - for (auto i : newvr) + + /* + for (auto pi : new_pir) { - auto dps = GetDistantPNums(i); + auto dps = GetDistantProcs(pi); if (dps.Size() > 0 && dps[0] < comm.Rank()) { - int master = comm.Size(); - for (int j = 0; j < dps.Size(); j++) - master = min (master, dps[j]); - if (master != dps[0]) - cout << "master not the first one !" << endl; - glob_vert[i] = recv_data[master][cnt[master]++]; + int master = dps[0]; + L2G(pi) = recv_data[master][cnt[master]++]; } } - + */ + for (auto pi : new_pir) + if (auto dps = GetDistantProcs(pi); dps.Size()) + if (int master = dps[0]; master < comm.Rank()) + L2G(pi) = recv_data[master][cnt[master]++]; + /* if (PointIndex::BASE==1) for (auto & i : glob_vert) @@ -208,13 +209,11 @@ namespace netgen Array index0(glob_vert.Size()); for (int pi : Range(index0)) index0[pi] = pi; - QuickSortI (FlatArray (glob_vert), index0); + QuickSortI (glob_vert, index0); - comm.Barrier(); - for (int i = 0; i+1 < glob_vert.Size(); i++) + for (size_t i = 0; i+1 < glob_vert.Size(); i++) if (glob_vert[index0[i]] > glob_vert[index0[i+1]]) cout << "wrong ordering" << endl; - comm.Barrier(); if (rank != 0) { @@ -272,7 +271,7 @@ namespace netgen // *testout << "l " << i << " globi "<< glob_vert[i] << " dist = " << loc2distvert[i] << endl; } - for (int i = 0; i+1 < glob_vert.Size(); i++) + for (size_t i = 0; i+1 < glob_vert.Size(); i++) if (glob_vert[i] > glob_vert[i+1]) cout << "wrong ordering of globvert" << endl; @@ -536,11 +535,11 @@ namespace netgen // build exchange vertices cnt_send = 0; for (PointIndex pi : mesh.Points().Range()) - for (int dist : GetDistantPNums(pi-PointIndex::BASE)) + for (int dist : GetDistantProcs(pi)) cnt_send[dist-1]++; TABLE dest2vert(cnt_send); for (PointIndex pi : mesh.Points().Range()) - for (int dist : GetDistantPNums(pi-PointIndex::BASE)) + for (int dist : GetDistantProcs(pi)) dest2vert.Add (dist-1, pi); for (PointIndex pi = PointIndex::BASE; pi < newnv+PointIndex::BASE; pi++) @@ -687,11 +686,11 @@ namespace netgen // build exchange vertices cnt_send = 0; for (PointIndex pi : mesh.Points().Range()) - for (int dist : GetDistantPNums(pi-PointIndex::BASE)) + for (int dist : GetDistantProcs(pi)) cnt_send[dist-1]++; TABLE dest2vert(cnt_send); for (PointIndex pi : mesh.Points().Range()) - for (int dist : GetDistantPNums(pi-PointIndex::BASE)) + for (int dist : GetDistantProcs(pi)) dest2vert.Add (dist-1, pi); MPI_Group_free(&MPI_LocalGroup); @@ -916,11 +915,11 @@ namespace netgen // build exchange vertices cnt_send = 0; for (PointIndex pi : mesh.Points().Range()) - for (int dist : GetDistantPNums(pi-PointIndex::BASE)) + for (int dist : GetDistantProcs(pi)) cnt_send[dist-1]++; TABLE dest2vert(cnt_send); for (PointIndex pi : mesh.Points().Range()) - for (int dist : GetDistantPNums(pi-PointIndex::BASE)) + for (int dist : GetDistantProcs(pi)) dest2vert.Add (dist-1, pi); // exchange edges diff --git a/libsrc/meshing/paralleltop.hpp b/libsrc/meshing/paralleltop.hpp index 26f3f143..90befebe 100644 --- a/libsrc/meshing/paralleltop.hpp +++ b/libsrc/meshing/paralleltop.hpp @@ -123,6 +123,10 @@ namespace netgen FlatArray GetDistantEdgeNums (int locnum) const { return loc2distedge[locnum]; } FlatArray GetDistantProcs (PointIndex pi) const { return loc2distvert[pi-PointIndex::BASE]; } + auto & L2G (PointIndex pi) { return glob_vert[pi-PointIndex::BASE]; } + auto L2G (PointIndex pi) const { return glob_vert[pi-PointIndex::BASE]; } + + [[deprecated("Use GetDistantProcs(..).Contains instead!")]] bool IsExchangeVert (int dest, int vnum) const { From 73846f23ae44a1db32dc9cf70b3dfc3831e62fc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20Sch=C3=B6berl?= Date: Sat, 29 Aug 2020 09:58:33 +0200 Subject: [PATCH 143/384] remove BaseDynamicTable, everything in template class --- libsrc/core/table.hpp | 545 +++++++++++++++++++++--------------------- 1 file changed, 266 insertions(+), 279 deletions(-) diff --git a/libsrc/core/table.hpp b/libsrc/core/table.hpp index a1033973..a1aac67e 100644 --- a/libsrc/core/table.hpp +++ b/libsrc/core/table.hpp @@ -20,76 +20,76 @@ namespace ngcore template -class FlatTable -{ -protected: - static constexpr IndexType BASE = IndexBASE(); - /// number of rows - size_t size; - /// pointer to first in row - size_t * index; - /// array of data - T * data; - -public: - FlatTable() = delete; - - NETGEN_INLINE FlatTable(size_t as, size_t * aindex, T * adata) - : size(as), index(aindex), data(adata) { ; } - - /// Size of table - NETGEN_INLINE size_t Size() const { return size; } - - /// Access entry - NETGEN_INLINE const FlatArray operator[] (IndexType i) const + class FlatTable { - i = i-BASE; - return FlatArray (index[i+1]-index[i], data+index[i]); - } + protected: + static constexpr IndexType BASE = IndexBASE(); + /// number of rows + size_t size; + /// pointer to first in row + size_t * index; + /// array of data + T * data; - NETGEN_INLINE T * Data() const { return data; } - - NETGEN_INLINE FlatArray AsArray() const - { - return FlatArray (index[size]-index[0], data+index[0]); - } - - NETGEN_INLINE FlatArray IndexArray() const - { - return FlatArray (size+1, index); - } - - /// takes range starting from position start of end-start elements - NETGEN_INLINE FlatTable Range (size_t start, size_t end) const - { - return FlatTable (end-start, index+start-BASE, data); - } - - /// takes range starting from position start of end-start elements - NETGEN_INLINE FlatTable Range (T_Range range) const - { - return FlatTable (range.Size(), index+range.First()-BASE, data); - } - - NETGEN_INLINE T_Range Range () const - { - return T_Range (BASE, size+BASE); - } - - class Iterator - { - const FlatTable & tab; - size_t row; public: - Iterator (const FlatTable & _tab, size_t _row) : tab(_tab), row(_row) { ; } - Iterator & operator++ () { ++row; return *this; } - FlatArray operator* () const { return tab[row]; } - bool operator!= (const Iterator & it2) { return row != it2.row; } - }; + FlatTable() = delete; - Iterator begin() const { return Iterator(*this, BASE); } - Iterator end() const { return Iterator(*this, BASE+size); } -}; + NETGEN_INLINE FlatTable(size_t as, size_t * aindex, T * adata) + : size(as), index(aindex), data(adata) { ; } + + /// Size of table + NETGEN_INLINE size_t Size() const { return size; } + + /// Access entry + NETGEN_INLINE const FlatArray operator[] (IndexType i) const + { + i = i-BASE; + return FlatArray (index[i+1]-index[i], data+index[i]); + } + + NETGEN_INLINE T * Data() const { return data; } + + NETGEN_INLINE FlatArray AsArray() const + { + return FlatArray (index[size]-index[0], data+index[0]); + } + + NETGEN_INLINE FlatArray IndexArray() const + { + return FlatArray (size+1, index); + } + + /// takes range starting from position start of end-start elements + NETGEN_INLINE FlatTable Range (size_t start, size_t end) const + { + return FlatTable (end-start, index+start-BASE, data); + } + + /// takes range starting from position start of end-start elements + NETGEN_INLINE FlatTable Range (T_Range range) const + { + return FlatTable (range.Size(), index+range.First()-BASE, data); + } + + NETGEN_INLINE T_Range Range () const + { + return T_Range (BASE, size+BASE); + } + + class Iterator + { + const FlatTable & tab; + size_t row; + public: + Iterator (const FlatTable & _tab, size_t _row) : tab(_tab), row(_row) { ; } + Iterator & operator++ () { ++row; return *this; } + FlatArray operator* () const { return tab[row]; } + bool operator!= (const Iterator & it2) { return row != it2.row; } + }; + + Iterator begin() const { return Iterator(*this, BASE); } + Iterator end() const { return Iterator(*this, BASE+size); } + }; NGCORE_API extern size_t * TablePrefixSum32 (FlatArray entrysize); NGCORE_API extern size_t * TablePrefixSum64 (FlatArray entrysize); @@ -105,106 +105,106 @@ public: { return TablePrefixSum64 (entrysize); } -/** - A compact Table container. - A table contains size entries of variable size. - The entry sizes must be known at construction. -*/ + /** + A compact Table container. + A table contains size entries of variable size. + The entry sizes must be known at construction. + */ template class Table : public FlatTable -{ -protected: - - using FlatTable::size; - using FlatTable::index; - using FlatTable::data; - -public: - /// - NETGEN_INLINE Table () : FlatTable (0,nullptr,nullptr) { ; } - /// Construct table of uniform entrysize - NETGEN_INLINE Table (size_t asize, size_t entrysize) - : FlatTable( asize, new size_t[asize+1], new T[asize*entrysize] ) { - for (size_t i : IntRange(size+1)) - index[i] = i*entrysize; - } + protected: - /// Construct table of variable entrysize - template - NETGEN_INLINE Table (FlatArray entrysize) - : FlatTable (0, nullptr, nullptr) - { - size = entrysize.Size(); - index = TablePrefixSum (FlatArray (entrysize.Size(), entrysize.Data())); - size_t cnt = index[size]; - data = new T[cnt]; - } + using FlatTable::size; + using FlatTable::index; + using FlatTable::data; - explicit NETGEN_INLINE Table (const Table & tab2) - : FlatTable(0, nullptr, nullptr) - { - size = tab2.Size(); + public: + /// + NETGEN_INLINE Table () : FlatTable (0,nullptr,nullptr) { ; } + /// Construct table of uniform entrysize + NETGEN_INLINE Table (size_t asize, size_t entrysize) + : FlatTable( asize, new size_t[asize+1], new T[asize*entrysize] ) + { + for (size_t i : IntRange(size+1)) + index[i] = i*entrysize; + } - index = new size_t[size+1]; - for (size_t i = 0; i <= size; i++) - index[i] = tab2.index[i]; + /// Construct table of variable entrysize + template + NETGEN_INLINE Table (FlatArray entrysize) + : FlatTable (0, nullptr, nullptr) + { + size = entrysize.Size(); + index = TablePrefixSum (FlatArray (entrysize.Size(), entrysize.Data())); + size_t cnt = index[size]; + data = new T[cnt]; + } - size_t cnt = index[size]; - data = new T[cnt]; - for (size_t i = 0; i < cnt; i++) - data[i] = tab2.data[i]; - } + explicit NETGEN_INLINE Table (const Table & tab2) + : FlatTable(0, nullptr, nullptr) + { + size = tab2.Size(); - NETGEN_INLINE Table (Table && tab2) - : FlatTable(0, nullptr, nullptr) - { - Swap (size, tab2.size); - Swap (index, tab2.index); - Swap (data, tab2.data); - } + index = new size_t[size+1]; + for (size_t i = 0; i <= size; i++) + index[i] = tab2.index[i]; - NETGEN_INLINE Table & operator= (Table && tab2) - { - Swap (size, tab2.size); - Swap (index, tab2.index); - Swap (data, tab2.data); - return *this; - } + size_t cnt = index[size]; + data = new T[cnt]; + for (size_t i = 0; i < cnt; i++) + data[i] = tab2.data[i]; + } + + NETGEN_INLINE Table (Table && tab2) + : FlatTable(0, nullptr, nullptr) + { + Swap (size, tab2.size); + Swap (index, tab2.index); + Swap (data, tab2.data); + } + + NETGEN_INLINE Table & operator= (Table && tab2) + { + Swap (size, tab2.size); + Swap (index, tab2.index); + Swap (data, tab2.data); + return *this; + } - /// Delete data - NETGEN_INLINE ~Table () - { - delete [] data; - delete [] index; - } + /// Delete data + NETGEN_INLINE ~Table () + { + delete [] data; + delete [] index; + } - /// Size of table - using FlatTable::Size; + /// Size of table + using FlatTable::Size; - /// number of elements in all rows - NETGEN_INLINE size_t NElements() const { return index[size]; } + /// number of elements in all rows + NETGEN_INLINE size_t NElements() const { return index[size]; } - using FlatTable::operator[]; -}; + using FlatTable::operator[]; + }; -/// Print table + /// Print table template inline ostream & operator<< (ostream & s, const Table & table) -{ - for (auto i : table.Range()) - { - s << i << ":"; - for (auto el : table[i]) - s << " " << el; - s << "\n"; - } - s << std::flush; - return s; -} + { + for (auto i : table.Range()) + { + s << i << ":"; + for (auto el : table[i]) + s << " " << el; + s << "\n"; + } + s << std::flush; + return s; + } @@ -349,32 +349,32 @@ public: }; -/// Base class to generic DynamicTable. -template - class BaseDynamicTable + + /** + A dynamic table class. + + A DynamicTable contains entries of variable size. Entry sizes can + be increased dynamically. + */ + template + class DynamicTable { protected: - static constexpr IndexType BASE = IndexBASE(); - - /// + static constexpr IndexType BASE = IndexBASE(); + struct linestruct { - /// int size; - /// int maxsize; - /// - void * col; + T * col; }; - /// Array data; - /// - char * oneblock; - + T * oneblock; + public: - /// - BaseDynamicTable (int size) + /// Creates table of size size + DynamicTable (int size = 0) : data(size) { for (auto & d : data) @@ -385,112 +385,36 @@ template } oneblock = nullptr; } - - /// - BaseDynamicTable (const Array & entrysizes, int elemsize) + + /// Creates table with a priori fixed entry sizes. + DynamicTable (const Array & entrysizes) : data(entrysizes.Size()) { - int cnt = 0; - int n = entrysizes.Size(); + size_t cnt = 0; + size_t n = entrysizes.Size(); for (auto es : entrysizes) cnt += es; - oneblock = new char[elemsize * cnt]; + oneblock = new T[cnt]; cnt = 0; for (auto i : Range(data)) { data[i].maxsize = entrysizes[i]; data[i].size = 0; - data[i].col = &oneblock[elemsize * cnt]; + data[i].col = &oneblock[cnt]; cnt += entrysizes[i]; } } - /// - ~BaseDynamicTable () + + ~DynamicTable () { if (oneblock) delete [] oneblock; else for (auto & d : data) - delete [] static_cast (d.col); + delete [] d.col; } - - /// Changes Size of table to size, deletes data - void SetSize (int size) - { - for (auto & d : data) - delete [] static_cast (d.col); - - data.SetSize(size); - for (auto & d : data) - { - d.maxsize = 0; - d.size = 0; - d.col = NULL; - } - } - - /// - void IncSize (IndexType i, int elsize) - { - NETGEN_CHECK_RANGE(i,BASE,data.Size()+BASE); - - linestruct & line = data[i]; - - if (line.size == line.maxsize) - { - void * p = new char [(2*line.maxsize+5) * elsize]; - - memcpy (p, line.col, line.maxsize * elsize); - delete [] static_cast (line.col); - line.col = p; - line.maxsize = 2*line.maxsize+5; - } - - line.size++; - } - - void DecSize (IndexType i) - { - NETGEN_CHECK_RANGE(i,BASE,data.Size()+BASE); - /* - if (i < 0 || i >= data.Size()) - { - std::cerr << "BaseDynamicTable::Dec: Out of range" << std::endl; - return; - } - */ - linestruct & line = data[i]; - - if (line.size == 0) - throw Exception ("BaseDynamicTable::Dec: EntrySize < 0"); - - line.size--; - } - }; - - - - /** - A dynamic table class. - - A DynamicTable contains entries of variable size. Entry sizes can - be increased dynamically. - */ -template -class DynamicTable : public BaseDynamicTable - { - using BaseDynamicTable::data; - using BaseDynamicTable::oneblock; - public: - /// Creates table of size size - DynamicTable (int size = 0) - : BaseDynamicTable (size) { } - - /// Creates table with a priori fixed entry sizes. - DynamicTable (const Array & entrysizes) - : BaseDynamicTable (entrysizes, sizeof(T)) { } DynamicTable & operator= (DynamicTable && tab2) { @@ -498,81 +422,144 @@ class DynamicTable : public BaseDynamicTable Swap (oneblock, tab2.oneblock); return *this; } + + /// Changes Size of table to size, deletes data + void SetSize (int size) + { + for (auto & d : data) + delete [] d.col; + data.SetSize(size); + for (auto & d : data) + { + d.maxsize = 0; + d.size = 0; + d.col = nullptr; + } + } + + /// + void IncSize (IndexType i) + { + NETGEN_CHECK_RANGE(i,BASE,data.Size()+BASE); + + linestruct & line = data[i]; + + if (line.size == line.maxsize) + { + T * p = new T[(2*line.maxsize+5)]; + for (size_t i = 0; i < line.maxsize; i++) + p[i] = std::move(line.col[i]); + // memcpy (p, line.col, line.maxsize * sizeof(T)); + delete [] line.col; + line.col = p; + line.maxsize = 2*line.maxsize+5; + } + + line.size++; + } + + void DecSize (IndexType i) + { + NETGEN_CHECK_RANGE(i,BASE,data.Size()+BASE); + linestruct & line = data[i]; + +#ifdef NETGEN_ENABLE_CHECK_RANGE + if (line.size == 0) + throw Exception ("BaseDynamicTable::Dec: EntrySize < 0"); +#endif + + line.size--; + } + + /// Inserts element acont into row i. Does not test if already used. void Add (IndexType i, const T & acont) { if (data[i].size == data[i].maxsize) - this->IncSize (i, sizeof (T)); + this->IncSize (i); else data[i].size++; - static_cast (data[i].col) [data[i].size-1] = acont; + data[i].col[data[i].size-1] = acont; } - + /// Inserts element acont into row i, iff not yet exists. void AddUnique (IndexType i, const T & cont) { int es = EntrySize (i); - int * line = const_cast (GetLine (i)); + T * line = data[i].col; for (int j = 0; j < es; j++) if (line[j] == cont) return; Add (i, cont); } - + /// Inserts element acont into row i. Does not test if already used. void AddEmpty (IndexType i) { - IncSize (i, sizeof (T)); + IncSize (i); } - + /** Set the nr-th element in the i-th row to acont. Does not check for overflow. */ void Set (IndexType i, int nr, const T & acont) - { static_cast (data[i].col)[nr] = acont; } + { + data[i].col[nr] = acont; + } /** Returns the nr-th element in the i-th row. - Does not check for overflow. */ + Does not check for overflow. */ const T & Get (IndexType i, int nr) const - { return static_cast (data[i].col)[nr]; } - - + { + return data[i].col[nr]; + } + + /** Returns pointer to the first element in row i. */ const T * GetLine (IndexType i) const - { return static_cast (data[i].col); } - - + { + return data[i].col; + } + /// Returns size of the table. - int Size () const - { return data.Size(); } - + size_t Size () const + { + return data.Size(); + } + /// Returns size of the i-th row. int EntrySize (IndexType i) const - { return data[i].size; } + { + return data[i].size; + } /// void DecEntrySize (IndexType i) - { DecSize(i); } - + { + DecSize(i); + } + /// Access entry i FlatArray operator[] (IndexType i) - { return FlatArray (data[i].size, static_cast (data[i].col)); } - + { + return FlatArray (data[i].size, data[i].col); + } + /* - typedef const FlatArray ConstFlatArray; - /// Access entry i - ConstFlatArray operator[] (int i) const - { return FlatArray (data[i].size, static_cast (data[i].col)); } + typedef const FlatArray ConstFlatArray; + /// Access entry i + ConstFlatArray operator[] (int i) const + { return FlatArray (data[i].size, static_cast (data[i].col)); } */ FlatArray operator[] (IndexType i) const - { return FlatArray (data[i].size, static_cast (data[i].col)); } + { + return FlatArray (data[i].size, data[i].col); + } }; - - /// Print table template inline ostream & operator<< (ostream & s, const DynamicTable & table) From 8840c519d3b8fc00be4b5744dda56e69c470b697 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20Sch=C3=B6berl?= Date: Sat, 29 Aug 2020 11:04:47 +0200 Subject: [PATCH 144/384] Min/Max of FlatArray, DynamicTable::ChangeSize --- libsrc/core/array.hpp | 16 +++++++++++++++ libsrc/core/table.hpp | 46 ++++++++++++++++++++++++++++++++++++++----- 2 files changed, 57 insertions(+), 5 deletions(-) diff --git a/libsrc/core/array.hpp b/libsrc/core/array.hpp index 3a775eea..28868d91 100644 --- a/libsrc/core/array.hpp +++ b/libsrc/core/array.hpp @@ -599,6 +599,22 @@ namespace ngcore template FlatArray View (FlatArray fa) { return fa; } + template + auto Max (FlatArray array, T max = std::numeric_limits::min()) -> T + { + for (auto & v : array) + if (v > max) max = v; + return max; + } + + template + auto Min (FlatArray array, T min = std::numeric_limits::max()) -> T + { + for (auto & v : array) + if (v < min) min = v; + return min; + } + /// print array template inline ostream & operator<< (ostream & s, const FlatArray & a) diff --git a/libsrc/core/table.hpp b/libsrc/core/table.hpp index a1aac67e..2bcd739a 100644 --- a/libsrc/core/table.hpp +++ b/libsrc/core/table.hpp @@ -370,7 +370,7 @@ namespace ngcore }; Array data; - T * oneblock; + T * oneblock = nullptr; public: /// Creates table of size size @@ -398,7 +398,7 @@ namespace ngcore oneblock = new T[cnt]; cnt = 0; - for (auto i : Range(data)) + for (auto i : data.Range()) { data[i].maxsize = entrysizes[i]; data[i].size = 0; @@ -407,6 +407,12 @@ namespace ngcore } } + DynamicTable (DynamicTable && tab2) + { + Swap (data, tab2.data); + Swap (oneblock, tab2.oneblock); + } + ~DynamicTable () { if (oneblock) @@ -437,7 +443,32 @@ namespace ngcore d.col = nullptr; } } - + + void ChangeSize (size_t size) + { + if (oneblock) + throw Exception ("cannot change size of oneblock dynamic table"); + + size_t oldsize = data.Size(); + if (size == oldsize) + return; + + if (size < oldsize) + for (int i = size; i < oldsize; i++) + delete [] data[i+BASE].col; + + data.SetSize(size); + + for (int i = oldsize; i < size; i++) + { + data[i+BASE].maxsize = 0; + data[i+BASE].size = 0; + data[i+BASE].col = nullptr; + } + } + + + /// void IncSize (IndexType i) { @@ -528,7 +559,12 @@ namespace ngcore { return data.Size(); } - + + auto Range () const + { + return data.Range(); + } + /// Returns size of the i-th row. int EntrySize (IndexType i) const { @@ -564,7 +600,7 @@ namespace ngcore template inline ostream & operator<< (ostream & s, const DynamicTable & table) { - for (int i = 0; i < table.Size(); i++) + for (auto i : Range(table)) { s << i << ":"; for (int j = 0; j < table[i].Size(); j++) From c8b8b3ddd353dd7ffa20620529237eb6e026f48b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20Sch=C3=B6berl?= Date: Sat, 29 Aug 2020 11:05:02 +0200 Subject: [PATCH 145/384] modernize paralleltop --- libsrc/meshing/paralleltop.cpp | 182 +++++++++++---------------------- 1 file changed, 58 insertions(+), 124 deletions(-) diff --git a/libsrc/meshing/paralleltop.cpp b/libsrc/meshing/paralleltop.cpp index c1b83abe..64f9fc0e 100644 --- a/libsrc/meshing/paralleltop.cpp +++ b/libsrc/meshing/paralleltop.cpp @@ -4,30 +4,6 @@ #include #include "paralleltop.hpp" -namespace ngcore -{ - - template - auto Max (FlatArray array) -> T - { - T max = std::numeric_limits::min(); - for (auto & v : array) - if (v > max) max = v; - return max; - } - - /* - template - auto Max (FlatArray array, TB initial) -> T - { - T max = initial; - for (auto & v : array) - if (v > max) max = v; - return max; - } - */ -} - namespace netgen { @@ -98,7 +74,8 @@ namespace netgen PointIndex(nv+PointIndex::BASE)); glob_vert.SetSize (nv); - glob_vert.Range(oldnv, nv) = -1; + for (auto pi : new_pir) + L2G(pi) = -1; int num_master_points = 0; @@ -139,17 +116,16 @@ namespace netgen nsend = 0; nrecv = 0; - /** Count send/recv size **/ + /** Count send/recv size **/ for (auto pi : new_pir) - { - auto dps = GetDistantProcs(pi); - if (!dps.Size()) continue; - if (rank < dps[0]) - for (auto p : dps) - nsend[p]++; - else - nrecv[dps[0]]++; - } + if (auto dps = GetDistantProcs(pi); dps.Size()) + { + if (rank < dps[0]) + for (auto p : dps) + nsend[p]++; + else + nrecv[dps[0]]++; + } Table send_data(nsend); Table recv_data(nrecv); @@ -176,50 +152,19 @@ namespace netgen Array cnt(comm.Size()); cnt = 0; - /* - for (auto pi : new_pir) - { - auto dps = GetDistantProcs(pi); - if (dps.Size() > 0 && dps[0] < comm.Rank()) - { - int master = dps[0]; - L2G(pi) = recv_data[master][cnt[master]++]; - } - } - */ for (auto pi : new_pir) if (auto dps = GetDistantProcs(pi); dps.Size()) if (int master = dps[0]; master < comm.Rank()) L2G(pi) = recv_data[master][cnt[master]++]; - /* - if (PointIndex::BASE==1) - for (auto & i : glob_vert) - i++; - */ - - /* - cout << "check ordering: " << endl; - for (int i = 0; i < glob_vert.Size()-1; i++) - if (glob_vert[i] > glob_vert[i+1]) - cout << "wrong ordering" << endl; - */ - // reorder following global ordering: Array index0(glob_vert.Size()); for (int pi : Range(index0)) index0[pi] = pi; QuickSortI (glob_vert, index0); - for (size_t i = 0; i+1 < glob_vert.Size(); i++) - if (glob_vert[index0[i]] > glob_vert[index0[i+1]]) - cout << "wrong ordering" << endl; - if (rank != 0) { - Array index(index0.Size()); - for (int i = 0; i < index0.Size(); i++) - index[i+PointIndex::BASE] = index0[i]+PointIndex::BASE; Array inv_index(index0.Size()); for (int i = 0; i < index0.Size(); i++) inv_index[index0[i]+PointIndex::BASE] = i+PointIndex::BASE; @@ -241,22 +186,17 @@ namespace netgen if (mesh.mlbetweennodes.Size() == mesh.Points().Size()) { - cout << "take care of multigrid table" << endl; NgArray,PointIndex::BASE> hml { mesh.mlbetweennodes }; for (PointIndex pi : Range(mesh.Points())) mesh.mlbetweennodes[inv_index[pi]] = hml[pi]; } - - // *testout << "index0 = " << endl << index0 << endl; // *testout << "loc2distvertold = " << endl; // for (auto i : Range(index0)) // *testout << "l " << i << " globi "<< glob_vert[i] << " dist = " << loc2distvert[i] << endl; - DynamicTable oldtable(loc2distvert.Size()); - for (size_t i = 0; i < loc2distvert.Size(); i++) - for (auto val : loc2distvert[i]) - oldtable.Add (i, val); + + DynamicTable oldtable = std::move(loc2distvert); loc2distvert = DynamicTable (oldtable.Size()); for (size_t i = 0; i < oldtable.Size(); i++) for (auto val : oldtable[index0[i]]) @@ -274,8 +214,6 @@ namespace netgen for (size_t i = 0; i+1 < glob_vert.Size(); i++) if (glob_vert[i] > glob_vert[i+1]) cout << "wrong ordering of globvert" << endl; - - // *testout << "new glob_vert = " << glob_vert << endl; } @@ -321,7 +259,7 @@ namespace netgen for (auto val : loc2distvert[i]) oldtable.Add (i, val); loc2distvert = DynamicTable (anv); - for (size_t i = 0; i < min(anv, oldtable.Size()); i++) + for (size_t i = 0; i < min(size_t(anv), oldtable.Size()); i++) for (auto val : oldtable[i]) loc2distvert.Add (i, val); } @@ -493,8 +431,6 @@ namespace netgen NgArray cnt_send(ntasks-1); - - // update new vertices after mesh-refinement if (mesh.mlbetweennodes.Size() > 0) { @@ -503,7 +439,8 @@ namespace netgen // cout << "UpdateCoarseGrid - vertices" << endl; int newnv = mesh.mlbetweennodes.Size(); - // loc2distvert.ChangeSize(mesh.mlbetweennodes.Size()); + loc2distvert.ChangeSize(mesh.mlbetweennodes.Size()); + /* DynamicTable oldtable(loc2distvert.Size()); for (size_t i = 0; i < loc2distvert.Size(); i++) for (auto val : loc2distvert[i]) @@ -512,9 +449,7 @@ namespace netgen for (size_t i = 0; i < min(loc2distvert.Size(), oldtable.Size()); i++) for (auto val : oldtable[i]) loc2distvert.Add (i, val); - - *testout << "extended loc2distver = " << endl << loc2distvert << endl; - + */ /* for (PointIndex pi = PointIndex::BASE; pi < newnv+PointIndex::BASE; pi++) { @@ -552,12 +487,14 @@ namespace netgen if (IsExchangeVert (dest, v1) && IsExchangeVert (dest, v2)) cnt_send[dest-1]++; */ - auto procs1 = GetDistantProcs(v1); - auto procs2 = GetDistantProcs(v2); - if (mesh.mlbetweennodes[pi][0] != PointIndex::BASE-1) - for (int p : procs1) - if (procs2.Contains(p)) - cnt_send[p-1]++; + if (v1.IsValid()) + { + auto procs1 = GetDistantProcs(v1); + auto procs2 = GetDistantProcs(v2); + for (int p : procs1) + if (procs2.Contains(p)) + cnt_send[p-1]++; + } } TABLE dest2pair(cnt_send); @@ -566,40 +503,34 @@ namespace netgen { PointIndex v1 = mesh.mlbetweennodes[pi][0]; PointIndex v2 = mesh.mlbetweennodes[pi][1]; - auto procs1 = GetDistantProcs(v1); - auto procs2 = GetDistantProcs(v2); + /* if (mesh.mlbetweennodes[pi][0] != PointIndex::BASE-1) for (int dest : GetDistantPNums(v1-PointIndex::BASE)) if (IsExchangeVert (dest, v1) && IsExchangeVert (dest, v2)) dest2pair.Add (dest-1, pi); */ - if (mesh.mlbetweennodes[pi][0] != PointIndex::BASE-1) - for (int p : procs1) - if (procs2.Contains(p)) - dest2pair.Add (p-1, pi); - } + if (v1.IsValid()) + { + auto procs1 = GetDistantProcs(v1); + auto procs2 = GetDistantProcs(v2); + for (int p : procs1) + if (procs2.Contains(p)) + dest2pair.Add (p-1, pi); + } + } cnt_send = 0; - int v1, v2; - for (PointIndex pi = PointIndex::BASE; pi < newnv+PointIndex::BASE; pi++) - { - // PointIndex v1 = mesh.mlbetweennodes[pi][0]; - // PointIndex v2 = mesh.mlbetweennodes[pi][1]; - auto [v1,v2] = mesh.mlbetweennodes[pi]; - auto procs1 = GetDistantProcs(v1); - auto procs2 = GetDistantProcs(v2); - /* - if (mesh.mlbetweennodes[pi][0] != PointIndex::BASE-1) - for (int dest : GetDistantPNums(v1-PointIndex::BASE)) - if (IsExchangeVert(dest, v2)) - cnt_send[dest-1]+=2; - */ - if (mesh.mlbetweennodes[pi][0] != PointIndex::BASE-1) - for (int p : procs1) - if (procs2.Contains(p)) - cnt_send[p-1]+=2; - } + for (PointIndex pi : mesh.mlbetweennodes.Range()) + if (auto [v1,v2] = mesh.mlbetweennodes[pi]; v1.IsValid()) + { + auto procs1 = GetDistantProcs(v1); + auto procs2 = GetDistantProcs(v2); + + for (int p : procs1) + if (procs2.Contains(p)) + cnt_send[p-1]+=2; + } TABLE send_verts(cnt_send); @@ -622,15 +553,18 @@ namespace netgen { PointIndex v1 = mesh.mlbetweennodes[pi][0]; PointIndex v2 = mesh.mlbetweennodes[pi][1]; - auto procs1 = GetDistantProcs(v1); - auto procs2 = GetDistantProcs(v2); - if (mesh.mlbetweennodes[pi][0] != PointIndex::BASE-1) - // if (IsExchangeVert (dest, v1) && IsExchangeVert (dest, v2)) - if (procs1.Contains(dest) && procs2.Contains(dest)) - { - send_verts.Add (dest-1, loc2exchange[v1]); - send_verts.Add (dest-1, loc2exchange[v2]); - } + + if (v1.IsValid()) + { + auto procs1 = GetDistantProcs(v1); + auto procs2 = GetDistantProcs(v2); + + if (procs1.Contains(dest) && procs2.Contains(dest)) + { + send_verts.Add (dest-1, loc2exchange[v1]); + send_verts.Add (dest-1, loc2exchange[v2]); + } + } } } @@ -657,7 +591,7 @@ namespace netgen { PointIndex v1 = mesh.mlbetweennodes[pi][0]; PointIndex v2 = mesh.mlbetweennodes[pi][1]; - if (mesh.mlbetweennodes[pi][0] != PointIndex::BASE-1) + if (v1.IsValid()) { INDEX_2 re(recvarray[ii], recvarray[ii+1]); INDEX_2 es(loc2exchange[v1], loc2exchange[v2]); From 020dd4373d80028124b8bfb772dd4afd33473c9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20Sch=C3=B6berl?= Date: Sat, 29 Aug 2020 12:36:45 +0200 Subject: [PATCH 146/384] DynamicTable: char-alloc if not trivially constructable --- libsrc/core/table.hpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/libsrc/core/table.hpp b/libsrc/core/table.hpp index 2bcd739a..8db44f9d 100644 --- a/libsrc/core/table.hpp +++ b/libsrc/core/table.hpp @@ -391,7 +391,7 @@ namespace ngcore : data(entrysizes.Size()) { size_t cnt = 0; - size_t n = entrysizes.Size(); + // size_t n = entrysizes.Size(); for (auto es : entrysizes) cnt += es; @@ -478,7 +478,11 @@ namespace ngcore if (line.size == line.maxsize) { - T * p = new T[(2*line.maxsize+5)]; + T * p; + if constexpr (std::is_default_constructible::value) + p = new T[(2*line.maxsize+5)]; + else + p = reinterpret_cast(new char[(2*line.maxsize+5)*sizeof(T)]); for (size_t i = 0; i < line.maxsize; i++) p[i] = std::move(line.col[i]); // memcpy (p, line.col, line.maxsize * sizeof(T)); From f45fbfd811a878089caa70fe942d592e0e71c303 Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Sat, 29 Aug 2020 15:37:48 +0200 Subject: [PATCH 147/384] operator== and better archive for BitArray --- libsrc/core/bitarray.cpp | 56 ++++++++++++++++++++++++++++------------ libsrc/core/bitarray.hpp | 7 ++--- 2 files changed, 43 insertions(+), 20 deletions(-) diff --git a/libsrc/core/bitarray.cpp b/libsrc/core/bitarray.cpp index db9fc114..2523ce5f 100644 --- a/libsrc/core/bitarray.cpp +++ b/libsrc/core/bitarray.cpp @@ -83,6 +83,18 @@ namespace ngcore return *this; } + bool BitArray :: operator==(const BitArray& other) const + { + if(size != other.Size()) + return false; + for(auto i : Range(size/CHAR_BIT)) + if(data[i] != other.data[i]) + return false; + for(auto i : Range(size%CHAR_BIT)) + if(Test(i + size * (size/CHAR_BIT)) != other.Test(i + size * (size/CHAR_BIT))) + return false; + return true; + } BitArray & BitArray :: operator= (const BitArray & ba2) { @@ -115,29 +127,39 @@ namespace ngcore return cnt; } - Archive & operator & (Archive & archive, BitArray & ba) + void BitArray :: DoArchive(Archive& archive) { - if (archive.Output()) + if(archive.GetVersion("netgen") >= "v6.2.2007-62") { - archive << ba.Size(); - for (size_t i = 0; i < ba.Size(); i++) - archive << ba[i]; + archive.NeedsVersion("netgen", "v6.2.2007-62"); + auto size = Size(); + archive & size; + if(archive.Input()) + SetSize(size); + archive.Do(data, size/CHAR_BIT+1); } else { - size_t size; - archive & size; - ba.SetSize (size); - ba.Clear(); - for (size_t i = 0; i < size; i++) + if (archive.Output()) { - bool b; - archive & b; - if (b) ba.SetBit(i); + throw Exception("should not get here"); + archive << Size(); + for (size_t i = 0; i < Size(); i++) + archive << (*this)[i]; + } + else + { + size_t size; + archive & size; + SetSize (size); + Clear(); + for (size_t i = 0; i < size; i++) + { + bool b; + archive & b; + if (b) SetBit(i); + } } } - return archive; } - - -} +} // namespace ngcore diff --git a/libsrc/core/bitarray.hpp b/libsrc/core/bitarray.hpp index 9c0823cf..dff55daf 100644 --- a/libsrc/core/bitarray.hpp +++ b/libsrc/core/bitarray.hpp @@ -131,6 +131,7 @@ public: return Test(i); } + bool operator==(const BitArray& other) const; /// invert all bits NGCORE_API BitArray & Invert (); @@ -145,6 +146,9 @@ public: NGCORE_API BitArray & operator= (const BitArray & ba2); NGCORE_API size_t NumSet () const; + + void DoArchive(Archive& archive); + private: /// unsigned char Mask (size_t i) const @@ -190,11 +194,8 @@ private: return res; } - NGCORE_API std::ostream & operator<<(std::ostream & s, const BitArray & ba); - NGCORE_API Archive & operator & (Archive & archive, BitArray & ba); - } // namespace ngcore #endif // NETGEN_CORE_BITARRAY From 55971b3ddef7db7c9c628223a80064a384d36081 Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Sat, 29 Aug 2020 15:38:03 +0200 Subject: [PATCH 148/384] HashArchive --- libsrc/core/archive.hpp | 43 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/libsrc/core/archive.hpp b/libsrc/core/archive.hpp index af7efc5e..76cb3567 100644 --- a/libsrc/core/archive.hpp +++ b/libsrc/core/archive.hpp @@ -910,6 +910,49 @@ namespace ngcore } }; + // HashArchive ================================================================= + // This class enables to easily create hashes for archivable objects by xoring + // threw its data + + class NGCORE_API HashArchive : public Archive + { + size_t hash_value; + char* h; + int offset; + public: + HashArchive() : Archive(true) + { h = (char*)&hash_value; } + + using Archive::operator&; + Archive & operator & (double & d) override { return ApplyHash(d); } + Archive & operator & (int & i) override { return ApplyHash(i); } + Archive & operator & (short & i) override { return ApplyHash(i); } + Archive & operator & (long & i) override { return ApplyHash(i); } + Archive & operator & (size_t & i) override { return ApplyHash(i); } + Archive & operator & (unsigned char & i) override { return ApplyHash(i); } + Archive & operator & (bool & b) override { return ApplyHash(b); } + Archive & operator & (std::string & str) override + { for(auto c : str) ApplyHash(c); return *this; } + Archive & operator & (char *& str) override + { char* s = str; while(*s != '\0') ApplyHash(*(s++)); return *this; } + + size_t GetHash() const { return hash_value; } + + private: + template + Archive& ApplyHash(T val) + { + auto n = sizeof(T); + char* pval = (char*)&val; + for(int i = 0; i < n; i++) + { + h[offset++] ^= pval[i]; + offset %= 8; + } + return *this; + } + }; + } // namespace ngcore #endif // NETGEN_CORE_ARCHIVE_HPP From deab89adf88544cb14464cbe3d872d2d42021dac Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Sat, 29 Aug 2020 16:19:45 +0200 Subject: [PATCH 149/384] add missing NGCORE_API and HashArchive & with const value --- libsrc/core/archive.hpp | 5 +++++ libsrc/core/bitarray.hpp | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/libsrc/core/archive.hpp b/libsrc/core/archive.hpp index 76cb3567..dc381a4a 100644 --- a/libsrc/core/archive.hpp +++ b/libsrc/core/archive.hpp @@ -936,6 +936,11 @@ namespace ngcore Archive & operator & (char *& str) override { char* s = str; while(*s != '\0') ApplyHash(*(s++)); return *this; } + // HashArchive can be used in const context + template + Archive & operator& (const T& val) const + { return (*this) & const_cast(val); } + size_t GetHash() const { return hash_value; } private: diff --git a/libsrc/core/bitarray.hpp b/libsrc/core/bitarray.hpp index dff55daf..4005fc81 100644 --- a/libsrc/core/bitarray.hpp +++ b/libsrc/core/bitarray.hpp @@ -131,7 +131,7 @@ public: return Test(i); } - bool operator==(const BitArray& other) const; + NGCORE_API bool operator==(const BitArray& other) const; /// invert all bits NGCORE_API BitArray & Invert (); @@ -147,7 +147,7 @@ public: NGCORE_API size_t NumSet () const; - void DoArchive(Archive& archive); + NGCORE_API void DoArchive(Archive& archive); private: /// From aac584a5aa40ad9823c33319f67e075fbd08395e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20Sch=C3=B6berl?= Date: Sat, 29 Aug 2020 18:16:25 +0200 Subject: [PATCH 150/384] identify vertices without sub-group --- libsrc/meshing/paralleltop.cpp | 343 +++++---------------------------- 1 file changed, 53 insertions(+), 290 deletions(-) diff --git a/libsrc/meshing/paralleltop.cpp b/libsrc/meshing/paralleltop.cpp index 64f9fc0e..54782f32 100644 --- a/libsrc/meshing/paralleltop.cpp +++ b/libsrc/meshing/paralleltop.cpp @@ -382,8 +382,6 @@ namespace netgen void ParallelMeshTopology :: IdentifyVerticesAfterRefinement() { static Timer t("ParallelTopology::UpdateCoarseGrid"); RegionTimer r(t); - // cout << "UpdateCoarseGrid" << endl; - // if (is_updated) return; NgMPI_Comm comm = mesh.GetCommunicator(); int id = comm.Rank(); @@ -399,68 +397,19 @@ namespace netgen (*testout) << "UPDATE COARSE GRID PARALLEL TOPOLOGY " << endl; if (id == 0) PrintMessage (1, "update parallel topology"); - - - // UpdateCoarseGridGlobal(); - - - // MPI_Barrier (MPI_COMM_WORLD); - - MPI_Group MPI_GROUP_comm; - MPI_Group MPI_LocalGroup; - MPI_Comm MPI_LocalComm1; - - int process_ranks[] = { 0 }; - MPI_Comm_group (comm, &MPI_GROUP_comm); - MPI_Group_excl (MPI_GROUP_comm, 1, process_ranks, &MPI_LocalGroup); - MPI_Comm_create (comm, MPI_LocalGroup, &MPI_LocalComm1); - - if (id == 0) - { - // SetNV(0); - // EnumeratePointsGlobally(); - return; - } - - NgMPI_Comm MPI_LocalComm(MPI_LocalComm1); - const MeshTopology & topology = mesh.GetTopology(); - NgArray cnt_send(ntasks-1); - + NgArray cnt_send(ntasks); + int maxsize = comm.AllReduce (mesh.mlbetweennodes.Size(), MPI_MAX); // update new vertices after mesh-refinement - if (mesh.mlbetweennodes.Size() > 0) + if (maxsize > 0) { - // *testout << "have to identify new vertices, nv = " << mesh.GetNV() << endl; - - // cout << "UpdateCoarseGrid - vertices" << endl; int newnv = mesh.mlbetweennodes.Size(); loc2distvert.ChangeSize(mesh.mlbetweennodes.Size()); - /* - DynamicTable oldtable(loc2distvert.Size()); - for (size_t i = 0; i < loc2distvert.Size(); i++) - for (auto val : loc2distvert[i]) - oldtable.Add (i, val); - loc2distvert = DynamicTable (mesh.mlbetweennodes.Size()); - for (size_t i = 0; i < min(loc2distvert.Size(), oldtable.Size()); i++) - for (auto val : oldtable[i]) - loc2distvert.Add (i, val); - */ - /* - for (PointIndex pi = PointIndex::BASE; pi < newnv+PointIndex::BASE; pi++) - { - PointIndex v1 = mesh.mlbetweennodes[pi][0]; - PointIndex v2 = mesh.mlbetweennodes[pi][1]; - if (mesh.mlbetweennodes[pi][0] != PointIndex::BASE-1) - for (int dest = 1; dest < ntasks; dest++) - if (IsExchangeVert (dest, v1) && IsExchangeVert (dest, v2)) - SetDistantPNum(dest, pi); - } - */ bool changed = true; while (changed) @@ -471,53 +420,32 @@ namespace netgen cnt_send = 0; for (PointIndex pi : mesh.Points().Range()) for (int dist : GetDistantProcs(pi)) - cnt_send[dist-1]++; + cnt_send[dist]++; TABLE dest2vert(cnt_send); for (PointIndex pi : mesh.Points().Range()) for (int dist : GetDistantProcs(pi)) - dest2vert.Add (dist-1, pi); + dest2vert.Add (dist, pi); for (PointIndex pi = PointIndex::BASE; pi < newnv+PointIndex::BASE; pi++) - { - PointIndex v1 = mesh.mlbetweennodes[pi][0]; - PointIndex v2 = mesh.mlbetweennodes[pi][1]; - /* - if (mesh.mlbetweennodes[pi][0] != PointIndex::BASE-1) - for (int dest : GetDistantPNums(v1-PointIndex::BASE)) - if (IsExchangeVert (dest, v1) && IsExchangeVert (dest, v2)) - cnt_send[dest-1]++; - */ - if (v1.IsValid()) - { - auto procs1 = GetDistantProcs(v1); - auto procs2 = GetDistantProcs(v2); - for (int p : procs1) - if (procs2.Contains(p)) - cnt_send[p-1]++; - } - } - - TABLE dest2pair(cnt_send); - // for (int dest = 1; dest < ntasks; dest++) - for (PointIndex pi = PointIndex::BASE; pi < newnv+PointIndex::BASE; pi++) - { - PointIndex v1 = mesh.mlbetweennodes[pi][0]; - PointIndex v2 = mesh.mlbetweennodes[pi][1]; + if (auto [v1,v2] = mesh.mlbetweennodes[pi]; v1.IsValid()) + { + auto procs1 = GetDistantProcs(v1); + auto procs2 = GetDistantProcs(v2); + for (int p : procs1) + if (procs2.Contains(p)) + cnt_send[p]++; + } - /* - if (mesh.mlbetweennodes[pi][0] != PointIndex::BASE-1) - for (int dest : GetDistantPNums(v1-PointIndex::BASE)) - if (IsExchangeVert (dest, v1) && IsExchangeVert (dest, v2)) - dest2pair.Add (dest-1, pi); - */ - if (v1.IsValid()) - { - auto procs1 = GetDistantProcs(v1); - auto procs2 = GetDistantProcs(v2); - for (int p : procs1) - if (procs2.Contains(p)) - dest2pair.Add (p-1, pi); - } + TABLE dest2pair(cnt_send); + + for (PointIndex pi : mesh.mlbetweennodes.Range()) + if (auto [v1,v2] = mesh.mlbetweennodes[pi]; v1.IsValid()) + { + auto procs1 = GetDistantProcs(v1); + auto procs2 = GetDistantProcs(v2); + for (int p : procs1) + if (procs2.Contains(p)) + dest2pair.Add (p, pi); } cnt_send = 0; @@ -529,65 +457,50 @@ namespace netgen for (int p : procs1) if (procs2.Contains(p)) - cnt_send[p-1]+=2; + cnt_send[p]+=2; } TABLE send_verts(cnt_send); - + NgArray loc2exchange(mesh.GetNV()); - for (int dest = 1; dest < ntasks; dest++) + + for (int dest = 0; dest < ntasks; dest++) if (dest != id) { loc2exchange = -1; int cnt = 0; - /* - for (PointIndex pi : mesh.Points().Range()) - if (IsExchangeVert(dest, pi)) - loc2exchange[pi] = cnt++; - */ - for (PointIndex pi : dest2vert[dest-1]) + for (PointIndex pi : dest2vert[dest]) loc2exchange[pi] = cnt++; - // for (PointIndex pi = PointIndex::BASE; pi < newnv+PointIndex::BASE; pi++) - for (PointIndex pi : dest2pair[dest-1]) - { - PointIndex v1 = mesh.mlbetweennodes[pi][0]; - PointIndex v2 = mesh.mlbetweennodes[pi][1]; - - if (v1.IsValid()) - { - auto procs1 = GetDistantProcs(v1); - auto procs2 = GetDistantProcs(v2); - - if (procs1.Contains(dest) && procs2.Contains(dest)) - { - send_verts.Add (dest-1, loc2exchange[v1]); - send_verts.Add (dest-1, loc2exchange[v2]); - } - } - } + for (PointIndex pi : dest2pair[dest]) + if (auto [v1,v2] = mesh.mlbetweennodes[pi]; v1.IsValid()) + { + auto procs1 = GetDistantProcs(v1); + auto procs2 = GetDistantProcs(v2); + + if (procs1.Contains(dest) && procs2.Contains(dest)) + { + send_verts.Add (dest, loc2exchange[v1]); + send_verts.Add (dest, loc2exchange[v2]); + } + } } - TABLE recv_verts(ntasks-1); - MyMPI_ExchangeTable (send_verts, recv_verts, MPI_TAG_MESH+9, MPI_LocalComm); - - for (int dest = 1; dest < ntasks; dest++) + TABLE recv_verts(ntasks); + MyMPI_ExchangeTable (send_verts, recv_verts, MPI_TAG_MESH+9, comm); + + for (int dest = 0; dest < ntasks; dest++) if (dest != id) { loc2exchange = -1; int cnt = 0; - /* - for (PointIndex pi : mesh.Points().Range()) - if (IsExchangeVert(dest, pi)) - loc2exchange[pi] = cnt++; - */ - for (PointIndex pi : dest2vert[dest-1]) + + for (PointIndex pi : dest2vert[dest]) loc2exchange[pi] = cnt++; - NgFlatArray recvarray = recv_verts[dest-1]; + NgFlatArray recvarray = recv_verts[dest]; for (int ii = 0; ii < recvarray.Size(); ii+=2) - for (PointIndex pi : dest2pair[dest-1]) - // for (PointIndex pi = PointIndex::BASE; pi < newnv+PointIndex::BASE; pi++) + for (PointIndex pi : dest2pair[dest]) { PointIndex v1 = mesh.mlbetweennodes[pi][0]; PointIndex v2 = mesh.mlbetweennodes[pi][1]; @@ -604,6 +517,8 @@ namespace netgen } } } + + changed = comm.AllReduce (changed, MPI_LOR); } } @@ -621,13 +536,13 @@ namespace netgen cnt_send = 0; for (PointIndex pi : mesh.Points().Range()) for (int dist : GetDistantProcs(pi)) - cnt_send[dist-1]++; + cnt_send[dist]++; TABLE dest2vert(cnt_send); for (PointIndex pi : mesh.Points().Range()) for (int dist : GetDistantProcs(pi)) - dest2vert.Add (dist-1, pi); + dest2vert.Add (dist, pi); - MPI_Group_free(&MPI_LocalGroup); + // MPI_Group_free(&MPI_LocalGroup); // MPI_Comm_free(&MPI_LocalComm); } @@ -680,158 +595,6 @@ namespace netgen NgArray cnt_send(ntasks-1); -#ifdef NONE - // update new vertices after mesh-refinement - if (mesh.mlbetweennodes.Size() > 0) - { - // cout << "UpdateCoarseGrid - vertices" << endl; - int newnv = mesh.mlbetweennodes.Size(); - - // loc2distvert.ChangeSize(mesh.mlbetweennodes.Size()); - DynamicTable oldtable(loc2distvert.Size()); - for (size_t i = 0; i < loc2distvert.Size(); i++) - for (auto val : loc2distvert[i]) - oldtable.Add (i, val); - loc2distvert = DynamicTable (mesh.mlbetweennodes.Size()); - for (size_t i = 0; i < min(loc2distvert.Size(), oldtable.Size()); i++) - for (auto val : oldtable[i]) - loc2distvert.Add (i, val); - - - - /* - for (PointIndex pi = PointIndex::BASE; pi < newnv+PointIndex::BASE; pi++) - { - PointIndex v1 = mesh.mlbetweennodes[pi][0]; - PointIndex v2 = mesh.mlbetweennodes[pi][1]; - if (mesh.mlbetweennodes[pi][0] != PointIndex::BASE-1) - for (int dest = 1; dest < ntasks; dest++) - if (IsExchangeVert (dest, v1) && IsExchangeVert (dest, v2)) - SetDistantPNum(dest, pi); - } - */ - - bool changed = true; - while (changed) - { - changed = false; - - // build exchange vertices - cnt_send = 0; - for (PointIndex pi : mesh.Points().Range()) - for (int dist : GetDistantPNums(pi-PointIndex::BASE)) - cnt_send[dist-1]++; - TABLE dest2vert(cnt_send); - for (PointIndex pi : mesh.Points().Range()) - for (int dist : GetDistantPNums(pi-PointIndex::BASE)) - dest2vert.Add (dist-1, pi); - - - for (PointIndex pi = PointIndex::BASE; pi < newnv+PointIndex::BASE; pi++) - { - PointIndex v1 = mesh.mlbetweennodes[pi][0]; - PointIndex v2 = mesh.mlbetweennodes[pi][1]; - if (mesh.mlbetweennodes[pi][0] != PointIndex::BASE-1) - // for (int dest = 1; dest < ntasks; dest++) - for (int dest : GetDistantPNums(v1-PointIndex::BASE)) - if (IsExchangeVert (dest, v1) && IsExchangeVert (dest, v2)) - cnt_send[dest-1]++; - } - - TABLE dest2pair(cnt_send); - // for (int dest = 1; dest < ntasks; dest++) - for (PointIndex pi = PointIndex::BASE; pi < newnv+PointIndex::BASE; pi++) - { - PointIndex v1 = mesh.mlbetweennodes[pi][0]; - PointIndex v2 = mesh.mlbetweennodes[pi][1]; - if (mesh.mlbetweennodes[pi][0] != PointIndex::BASE-1) - for (int dest : GetDistantPNums(v1-PointIndex::BASE)) - if (IsExchangeVert (dest, v1) && IsExchangeVert (dest, v2)) - dest2pair.Add (dest-1, pi); - } - - cnt_send = 0; - int v1, v2; - for (PointIndex pi = PointIndex::BASE; pi < newnv+PointIndex::BASE; pi++) - { - PointIndex v1 = mesh.mlbetweennodes[pi][0]; - PointIndex v2 = mesh.mlbetweennodes[pi][1]; - if (mesh.mlbetweennodes[pi][0] != PointIndex::BASE-1) - for (int dest : GetDistantPNums(v1-PointIndex::BASE)) - if (IsExchangeVert(dest, v2)) - cnt_send[dest-1]+=2; - } - - TABLE send_verts(cnt_send); - - NgArray loc2exchange(mesh.GetNV()); - for (int dest = 1; dest < ntasks; dest++) - if (dest != id) - { - loc2exchange = -1; - int cnt = 0; - /* - for (PointIndex pi : mesh.Points().Range()) - if (IsExchangeVert(dest, pi)) - loc2exchange[pi] = cnt++; - */ - for (PointIndex pi : dest2vert[dest-1]) - loc2exchange[pi] = cnt++; - - // for (PointIndex pi = PointIndex::BASE; pi < newnv+PointIndex::BASE; pi++) - for (PointIndex pi : dest2pair[dest-1]) - { - PointIndex v1 = mesh.mlbetweennodes[pi][0]; - PointIndex v2 = mesh.mlbetweennodes[pi][1]; - if (mesh.mlbetweennodes[pi][0] != PointIndex::BASE-1) - if (IsExchangeVert (dest, v1) && IsExchangeVert (dest, v2)) - { - send_verts.Add (dest-1, loc2exchange[v1]); - send_verts.Add (dest-1, loc2exchange[v2]); - } - } - } - - TABLE recv_verts(ntasks-1); - MyMPI_ExchangeTable (send_verts, recv_verts, MPI_TAG_MESH+9, MPI_LocalComm); - - for (int dest = 1; dest < ntasks; dest++) - if (dest != id) - { - loc2exchange = -1; - int cnt = 0; - /* - for (PointIndex pi : mesh.Points().Range()) - if (IsExchangeVert(dest, pi)) - loc2exchange[pi] = cnt++; - */ - for (PointIndex pi : dest2vert[dest-1]) - loc2exchange[pi] = cnt++; - - NgFlatArray recvarray = recv_verts[dest-1]; - for (int ii = 0; ii < recvarray.Size(); ii+=2) - for (PointIndex pi : dest2pair[dest-1]) - // for (PointIndex pi = PointIndex::BASE; pi < newnv+PointIndex::BASE; pi++) - { - PointIndex v1 = mesh.mlbetweennodes[pi][0]; - PointIndex v2 = mesh.mlbetweennodes[pi][1]; - if (mesh.mlbetweennodes[pi][0] != PointIndex::BASE-1) - { - INDEX_2 re(recvarray[ii], recvarray[ii+1]); - INDEX_2 es(loc2exchange[v1], loc2exchange[v2]); - if (es == re && !IsExchangeVert(dest, pi)) - { - SetDistantPNum(dest, pi); - changed = true; - } - } - } - } - } - } -#endif - - // NgArray sendarray, recvarray; // cout << "UpdateCoarseGrid - edges" << endl; From 0b74e3cbdc14170fc688d385c9ef3915c7e9ec8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20Sch=C3=B6berl?= Date: Sat, 29 Aug 2020 18:24:01 +0200 Subject: [PATCH 151/384] identify edges/faces without sub-group --- libsrc/meshing/paralleltop.cpp | 79 +++++++++++++++++----------------- 1 file changed, 40 insertions(+), 39 deletions(-) diff --git a/libsrc/meshing/paralleltop.cpp b/libsrc/meshing/paralleltop.cpp index 54782f32..5cf4044a 100644 --- a/libsrc/meshing/paralleltop.cpp +++ b/libsrc/meshing/paralleltop.cpp @@ -572,7 +572,7 @@ namespace netgen // UpdateCoarseGridGlobal(); - + /* // MPI_Barrier (MPI_COMM_WORLD); MPI_Group MPI_GROUP_comm; @@ -590,10 +590,11 @@ namespace netgen // EnumeratePointsGlobally(); return; } + */ const MeshTopology & topology = mesh.GetTopology(); - NgArray cnt_send(ntasks-1); + NgArray cnt_send(ntasks); // NgArray sendarray, recvarray; // cout << "UpdateCoarseGrid - edges" << endl; @@ -613,11 +614,11 @@ namespace netgen cnt_send = 0; for (PointIndex pi : mesh.Points().Range()) for (int dist : GetDistantProcs(pi)) - cnt_send[dist-1]++; + cnt_send[dist]++; TABLE dest2vert(cnt_send); for (PointIndex pi : mesh.Points().Range()) for (int dist : GetDistantProcs(pi)) - dest2vert.Add (dist-1, pi); + dest2vert.Add (dist, pi); // exchange edges cnt_send = 0; @@ -633,7 +634,7 @@ namespace netgen */ for (auto p : GetDistantProcs(v1)) if (GetDistantProcs(v2).Contains(p)) - cnt_send[p-1]+=1; + cnt_send[p]+=1; } TABLE dest2edge(cnt_send); @@ -643,51 +644,51 @@ namespace netgen for (int edge = 1; edge <= ned; edge++) { topology.GetEdgeVertices (edge, v1, v2); - for (int dest = 1; dest < ntasks; dest++) + for (int dest = 0; dest < ntasks; dest++) // if (IsExchangeVert (dest, v1) && IsExchangeVert (dest, v2)) if (GetDistantProcs(v1).Contains(dest) && GetDistantProcs(v2).Contains(dest)) - dest2edge.Add (dest-1, edge); + dest2edge.Add (dest, edge); } NgArray loc2exchange(mesh.GetNV()); - for (int dest = 1; dest < ntasks; dest++) + for (int dest = 0; dest < ntasks; dest++) { loc2exchange = -1; int cnt = 0; - for (PointIndex pi : dest2vert[dest-1]) + for (PointIndex pi : dest2vert[dest]) loc2exchange[pi] = cnt++; - for (int edge : dest2edge[dest-1]) + for (int edge : dest2edge[dest]) { topology.GetEdgeVertices (edge, v1, v2); // if (IsExchangeVert (dest, v1) && IsExchangeVert (dest, v2)) if (GetDistantProcs(v1).Contains(dest) && GetDistantProcs(v2).Contains(dest)) { - send_edges.Add (dest-1, loc2exchange[v1]); - send_edges.Add (dest-1, loc2exchange[v2]); + send_edges.Add (dest, loc2exchange[v1]); + send_edges.Add (dest, loc2exchange[v2]); } } } // cout << "UpdateCoarseGrid - edges mpi-exchange" << endl; - TABLE recv_edges(ntasks-1); - MyMPI_ExchangeTable (send_edges, recv_edges, MPI_TAG_MESH+9, MPI_LocalComm); + TABLE recv_edges(ntasks); + MyMPI_ExchangeTable (send_edges, recv_edges, MPI_TAG_MESH+9, comm); // cout << "UpdateCoarseGrid - edges mpi-exchange done" << endl; - for (int dest = 1; dest < ntasks; dest++) + for (int dest = 0; dest < ntasks; dest++) { - auto ex2loc = dest2vert[dest-1]; + auto ex2loc = dest2vert[dest]; if (ex2loc.Size() == 0) continue; - INDEX_2_CLOSED_HASHTABLE vert2edge(2*dest2edge[dest-1].Size()+10); - for (int edge : dest2edge[dest-1]) + INDEX_2_CLOSED_HASHTABLE vert2edge(2*dest2edge[dest].Size()+10); + for (int edge : dest2edge[dest]) { topology.GetEdgeVertices (edge, v1, v2); vert2edge.Set(INDEX_2(v1,v2), edge); } - NgFlatArray recvarray = recv_edges[dest-1]; + NgFlatArray recvarray = recv_edges[dest]; for (int ii = 0; ii < recvarray.Size(); ii+=2) { INDEX_2 re(ex2loc[recvarray[ii]], @@ -712,7 +713,7 @@ namespace netgen for (int face = 1; face <= nfa; face++) { topology.GetFaceVertices (face, verts); - for (int dest = 1; dest < ntasks; dest++) + for (int dest = 0; dest < ntasks; dest++) if (dest != id) /* if (IsExchangeVert (dest, verts[0]) && @@ -722,14 +723,14 @@ namespace netgen if (GetDistantProcs (verts[0]).Contains(dest) && GetDistantProcs (verts[1]).Contains(dest) && GetDistantProcs (verts[2]).Contains(dest)) - cnt_send[dest-1]++; + cnt_send[dest]++; } TABLE dest2face(cnt_send); for (int face = 1; face <= nfa; face++) { topology.GetFaceVertices (face, verts); - for (int dest = 1; dest < ntasks; dest++) + for (int dest = 0; dest < ntasks; dest++) if (dest != id) /* if (IsExchangeVert (dest, verts[0]) && @@ -739,23 +740,23 @@ namespace netgen if (GetDistantProcs (verts[0]).Contains(dest) && GetDistantProcs (verts[1]).Contains(dest) && GetDistantProcs (verts[2]).Contains(dest)) - dest2face.Add(dest-1, face); + dest2face.Add(dest, face); } for (int & c : cnt_send) c*=3; TABLE send_faces(cnt_send); NgArray loc2exchange(mesh.GetNV()); - for (int dest = 1; dest < ntasks; dest++) + for (int dest = 0; dest < ntasks; dest++) if (dest != id) { - if (dest2vert[dest-1].Size() == 0) continue; + if (dest2vert[dest].Size() == 0) continue; loc2exchange = -1; int cnt = 0; - for (PointIndex pi : dest2vert[dest-1]) + for (PointIndex pi : dest2vert[dest]) loc2exchange[pi] = cnt++; - for (int face : dest2face[dest-1]) + for (int face : dest2face[dest]) { topology.GetFaceVertices (face, verts); /* @@ -767,31 +768,31 @@ namespace netgen GetDistantProcs (verts[1]).Contains(dest) && GetDistantProcs (verts[2]).Contains(dest)) { - send_faces.Add (dest-1, loc2exchange[verts[0]]); - send_faces.Add (dest-1, loc2exchange[verts[1]]); - send_faces.Add (dest-1, loc2exchange[verts[2]]); + send_faces.Add (dest, loc2exchange[verts[0]]); + send_faces.Add (dest, loc2exchange[verts[1]]); + send_faces.Add (dest, loc2exchange[verts[2]]); } } } // cout << "UpdateCoarseGrid - faces mpi-exchange" << endl; - TABLE recv_faces(ntasks-1); - MyMPI_ExchangeTable (send_faces, recv_faces, MPI_TAG_MESH+9, MPI_LocalComm); + TABLE recv_faces(ntasks); + MyMPI_ExchangeTable (send_faces, recv_faces, MPI_TAG_MESH+9, comm); // cout << "UpdateCoarseGrid - faces mpi-exchange done" << endl; - for (int dest = 1; dest < ntasks; dest++) + for (int dest = 0; dest < ntasks; dest++) { - auto ex2loc = dest2vert[dest-1]; + auto ex2loc = dest2vert[dest]; if (ex2loc.Size() == 0) continue; - INDEX_3_CLOSED_HASHTABLE vert2face(2*dest2face[dest-1].Size()+10); - for (int face : dest2face[dest-1]) + INDEX_3_CLOSED_HASHTABLE vert2face(2*dest2face[dest].Size()+10); + for (int face : dest2face[dest]) { topology.GetFaceVertices (face, verts); vert2face.Set(INDEX_3(verts[0], verts[1], verts[2]), face); } - NgFlatArray recvarray = recv_faces[dest-1]; + NgFlatArray recvarray = recv_faces[dest]; for (int ii = 0; ii < recvarray.Size(); ii+=3) { INDEX_3 re(ex2loc[recvarray[ii]], @@ -808,8 +809,8 @@ namespace netgen // EnumeratePointsGlobally(); is_updated = true; - MPI_Group_free(&MPI_LocalGroup); - MPI_Comm_free(&MPI_LocalComm); + // MPI_Group_free(&MPI_LocalGroup); + // MPI_Comm_free(&MPI_LocalComm); } } From 0fe20c9deee3fec0e3ed0129a9ac87ef8552123c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20Sch=C3=B6berl?= Date: Sat, 29 Aug 2020 20:56:29 +0200 Subject: [PATCH 152/384] set ParallelTop functions --- libsrc/meshing/curvedelems.cpp | 20 ++++++------ libsrc/meshing/parallelmesh.cpp | 12 ++++--- libsrc/meshing/paralleltop.cpp | 20 +++++++++--- libsrc/meshing/paralleltop.hpp | 55 ++++++++++++++++++++++++--------- 4 files changed, 74 insertions(+), 33 deletions(-) diff --git a/libsrc/meshing/curvedelems.cpp b/libsrc/meshing/curvedelems.cpp index 43628d3e..91f3c473 100644 --- a/libsrc/meshing/curvedelems.cpp +++ b/libsrc/meshing/curvedelems.cpp @@ -645,10 +645,10 @@ namespace netgen if (ntasks > 1 && working) { for (int e = 0; e < edgeorder.Size(); e++) - for (int proc : partop.GetDistantEdgeNums(e)) + for (int proc : partop.GetDistantEdgeProcs(e)) send_orders.Add (proc, edgeorder[e]); for (int f = 0; f < faceorder.Size(); f++) - for (int proc : partop.GetDistantFaceNums(f)) + for (int proc : partop.GetDistantFaceProcs(f)) send_orders.Add (proc, faceorder[f]); } @@ -660,10 +660,10 @@ namespace netgen NgArray cnt(ntasks); cnt = 0; for (int e = 0; e < edgeorder.Size(); e++) - for (auto proc : partop.GetDistantEdgeNums(e)) + for (auto proc : partop.GetDistantEdgeProcs(e)) edgeorder[e] = max(edgeorder[e], recv_orders[proc][cnt[proc]++]); for (int f = 0; f < faceorder.Size(); f++) - for (auto proc : partop.GetDistantFaceNums(f)) + for (auto proc : partop.GetDistantFaceProcs(f)) faceorder[f] = max(faceorder[f], recv_orders[proc][cnt[proc]++]); } #endif @@ -751,7 +751,7 @@ namespace netgen TABLE senddata(ntasks), recvdata(ntasks); if (working) for (int e = 0; e < nedges; e++) - for (int proc : partop.GetDistantEdgeNums(e)) + for (int proc : partop.GetDistantEdgeProcs(e)) { senddata.Add (proc, surfnr[e]); if (surfnr[e] != -1) @@ -771,7 +771,7 @@ namespace netgen cnt = 0; if (working) for (int e = 0; e < nedges; e++) - for (int proc : partop.GetDistantEdgeNums(e)) + for (int proc : partop.GetDistantEdgeProcs(e)) { int surfnr1 = recvdata[proc][cnt[proc]++]; if (surfnr1 != -1) @@ -946,7 +946,7 @@ namespace netgen TABLE senddata(ntasks), recvdata(ntasks); if (working) for (int e = 0; e < nedges; e++) - for (int proc : partop.GetDistantEdgeNums(e)) + for (int proc : partop.GetDistantEdgeProcs(e)) { senddata.Add (proc, use_edge[e]); if (use_edge[e]) @@ -972,7 +972,7 @@ namespace netgen cnt = 0; if (working) for (int e = 0; e < edge_surfnr1.Size(); e++) - for (int proc : partop.GetDistantEdgeNums(e)) + for (int proc : partop.GetDistantEdgeProcs(e)) { int get_edge = int(recvdata[proc][cnt[proc]++]); if (get_edge) @@ -1148,7 +1148,7 @@ namespace netgen if (ntasks > 1 && working) { for (int f = 0; f < nfaces; f++) - for (int proc : partop.GetDistantFaceNums(f)) + for (int proc : partop.GetDistantFaceProcs(f)) send_surfnr.Add (proc, surfnr[f]); } @@ -1160,7 +1160,7 @@ namespace netgen NgArray cnt(ntasks); cnt = 0; for (int f = 0; f < nfaces; f++) - for (int proc : partop.GetDistantFaceNums(f)) + for (int proc : partop.GetDistantFaceProcs(f)) surfnr[f] = max(surfnr[f], recv_surfnr[proc][cnt[proc]++]); } #endif diff --git a/libsrc/meshing/parallelmesh.cpp b/libsrc/meshing/parallelmesh.cpp index 62f482c1..8f060a1b 100644 --- a/libsrc/meshing/parallelmesh.cpp +++ b/libsrc/meshing/parallelmesh.cpp @@ -278,7 +278,8 @@ namespace netgen vert_flag[vertex] = dest; num_verts_on_proc[dest]++; num_procs_on_vert[vertex]++; - GetParallelTopology().SetDistantPNum (dest, vertex); + // GetParallelTopology().SetDistantPNum (dest, vertex); + GetParallelTopology().AddDistantProc (PointIndex(vertex), dest); } }; countit(vertex, dest); @@ -870,7 +871,8 @@ namespace netgen for (int vert = 0; vert < numvert; vert++) { int globvert = verts[vert] + IndexBASE(); - paralleltop->SetLoc2Glob_Vert ( vert+1, globvert ); + // paralleltop->SetLoc2Glob_Vert ( vert+1, globvert ); + paralleltop->L2G (PointIndex(vert+PointIndex::BASE)) = globvert; glob2loc_vert_ht.Set (globvert, vert+1); } @@ -902,16 +904,18 @@ namespace netgen } } - Array dist_pnums; + Array dist_pnums; comm.Recv (dist_pnums, 0, MPI_TAG_MESH+1); for (int hi = 0; hi < dist_pnums.Size(); hi += 3) paralleltop -> - SetDistantPNum (dist_pnums[hi+1], dist_pnums[hi]); // , dist_pnums[hi+2]); + // SetDistantPNum (dist_pnums[hi+1], dist_pnums[hi]); // , dist_pnums[hi+2]); + AddDistantProc (PointIndex(dist_pnums[hi]), dist_pnums[hi+1]); NgProfiler::StopTimer (timer_pts); *testout << "got " << numvert << " vertices" << endl; + { Array elarray; comm.Recv (elarray, 0, MPI_TAG_MESH+2); diff --git a/libsrc/meshing/paralleltop.cpp b/libsrc/meshing/paralleltop.cpp index 5cf4044a..08698e5d 100644 --- a/libsrc/meshing/paralleltop.cpp +++ b/libsrc/meshing/paralleltop.cpp @@ -211,12 +211,18 @@ namespace netgen // *testout << "l " << i << " globi "<< glob_vert[i] << " dist = " << loc2distvert[i] << endl; } + /* for (size_t i = 0; i+1 < glob_vert.Size(); i++) if (glob_vert[i] > glob_vert[i+1]) cout << "wrong ordering of globvert" << endl; + */ + if (glob_vert.Size() > 1) + for (auto i : Range(glob_vert).Modify(0,-1)) + if (glob_vert[i] > glob_vert[i+1]) + cout << "wrong ordering of globvert" << endl; } - + /* void ParallelMeshTopology :: SetDistantFaceNum (int dest, int locnum) { for ( int i = 0; i < loc2distface[locnum-1].Size(); i+=1 ) @@ -241,7 +247,8 @@ namespace netgen return; loc2distedge.Add (locnum-1, dest); } - + */ + void ParallelMeshTopology :: SetNV_Loc2Glob (int anv) { glob_vert.SetSize(anv); @@ -379,6 +386,7 @@ namespace netgen is_updated = true; } + void ParallelMeshTopology :: IdentifyVerticesAfterRefinement() { static Timer t("ParallelTopology::UpdateCoarseGrid"); RegionTimer r(t); @@ -511,7 +519,8 @@ namespace netgen // if (es == re && !IsExchangeVert(dest, pi)) if (es == re && !GetDistantProcs(pi).Contains(dest)) { - SetDistantPNum(dest, pi); + // SetDistantPNum(dest, pi); + AddDistantProc (pi, dest); changed = true; } } @@ -694,7 +703,8 @@ namespace netgen INDEX_2 re(ex2loc[recvarray[ii]], ex2loc[recvarray[ii+1]]); if (vert2edge.Used(re)) - SetDistantEdgeNum(dest, vert2edge.Get(re)); + // SetDistantEdgeNum(dest, vert2edge.Get(re)); + AddDistantEdgeProc(vert2edge.Get(re)-1, dest); } } @@ -799,7 +809,7 @@ namespace netgen ex2loc[recvarray[ii+1]], ex2loc[recvarray[ii+2]]); if (vert2face.Used(re)) - SetDistantFaceNum(dest, vert2face.Get(re)); + AddDistantFaceProc(vert2face.Get(re)-1, dest); } } diff --git a/libsrc/meshing/paralleltop.hpp b/libsrc/meshing/paralleltop.hpp index 90befebe..f6826328 100644 --- a/libsrc/meshing/paralleltop.hpp +++ b/libsrc/meshing/paralleltop.hpp @@ -16,9 +16,11 @@ namespace netgen */ DynamicTable loc2distvert; - TABLE loc2distedge, loc2distface; + DynamicTable loc2distedge, loc2distface; Array glob_vert; + + // will get rid of them NgArray glob_edge, glob_face; NgArray glob_el, glob_surfel, glob_segm; @@ -35,9 +37,21 @@ namespace netgen void UpdateCoarseGrid(); void UpdateCoarseGridGlobal(); void IdentifyVerticesAfterRefinement(); - // bool DoCoarseUpdate() const { return !coarseupdate; } + void EnumeratePointsGlobally (); + + void AddDistantProc (PointIndex pi, int proc) { loc2distvert.AddUnique (pi-PointIndex::BASE, proc); } + void AddDistantFaceProc (int edge, int proc) { loc2distface.AddUnique (edge, proc); } + void AddDistantEdgeProc (int face, int proc) { loc2distedge.AddUnique (face, proc); } + + FlatArray GetDistantProcs (PointIndex pi) const { return loc2distvert[pi-PointIndex::BASE]; } + FlatArray GetDistantFaceProcs (int locnum) const { return loc2distface[locnum]; } + FlatArray GetDistantEdgeProcs (int locnum) const { return loc2distedge[locnum]; } + + auto & L2G (PointIndex pi) { return glob_vert[pi-PointIndex::BASE]; } + auto L2G (PointIndex pi) const { return glob_vert[pi-PointIndex::BASE]; } + /// set number of local vertices, reset sizes of loc2dist_vert, isexchangevert... void SetNV (int anv); @@ -46,6 +60,21 @@ namespace netgen void SetNSE (int anse); void SetNSegm (int anseg); + [[deprecated("Use AddDistantFaceProc instead!")]] + void SetDistantFaceNum (int dest, int locnum) { loc2distface.AddUnique (locnum-1, dest); } + [[deprecated("Use AddDistantProc instead!")]] + void SetDistantPNum (int dest, int locnum) { loc2distvert.AddUnique (locnum-1, dest); } + [[deprecated("Use AddDistantEdgeProc instead!")]] + void SetDistantEdgeNum (int dest, int locnum) { loc2distedge.AddUnique (locnum-1, dest); } + + [[deprecated("Use GetDistantFaceProcx instead!")]] + FlatArray GetDistantFaceNums (int locnum) const { return loc2distface[locnum]; } + [[deprecated("Use GetDistantEdgeProcx instead!")]] + FlatArray GetDistantEdgeNums (int locnum) const { return loc2distedge[locnum]; } + + + + [[deprecated("Use L2G(pi) instead!")]] void SetLoc2Glob_Vert (int locnum, int globnum) { glob_vert[locnum-1] = globnum; } [[deprecated("Try to avoid global enumration!")]] void SetLoc2Glob_Edge (int locnum, int globnum) { glob_edge[locnum-1] = globnum; } @@ -68,12 +97,7 @@ namespace netgen [[deprecated("Try to avoid global enumration!")]] int GetGlobalSElNum (int locnum) const { return glob_surfel[locnum-1]; } - - void EnumeratePointsGlobally (); - void SetDistantFaceNum (int dest, int locnum); - void SetDistantPNum (int dest, int locnum); - void SetDistantEdgeNum (int dest, int locnum); [[deprecated("Use GetDistantPNums(locnum).Size() instead!")]] int GetNDistantPNums (int locpnum) const { return loc2distvert[locpnum-1].Size(); } @@ -101,7 +125,11 @@ namespace netgen [[deprecated("Use GetDistantFaceNums(locnum) -> FlatArray instead!")]] void GetDistantFaceNums (int locfacenum, NgArray & distfacenums ) const { - distfacenums = loc2distface[locfacenum-1]; + // distfacenums = loc2distface[locfacenum-1]; + auto loc = loc2distface[locfacenum-1]; + distfacenums.SetSize (loc.Size()); + for (int i = 0; i < loc.Size(); i++) + distfacenums[i] = loc[i]; } [[deprecated("Use GetDistantEdgeNums(locnum) -> FlatArray instead!")]] @@ -114,17 +142,16 @@ namespace netgen [[deprecated("Use GetDistantEdgeNums(locnum) -> FlatArray instead!")]] void GetDistantEdgeNums (int locedgenum, NgArray & distedgenums ) const { - distedgenums = loc2distedge[locedgenum-1]; + // distedgenums = loc2distedge[locedgenum-1]; + auto loc = loc2distedge[locedgenum-1]; + distedgenums.SetSize (loc.Size()); + for (int i = 0; i < loc.Size(); i++) + distedgenums[i] = loc[i]; } [[deprecated("Use GetDistantProcs(..)!")]] FlatArray GetDistantPNums (int locnum) const { return loc2distvert[locnum]; } - FlatArray GetDistantFaceNums (int locnum) const { return loc2distface[locnum]; } - FlatArray GetDistantEdgeNums (int locnum) const { return loc2distedge[locnum]; } - FlatArray GetDistantProcs (PointIndex pi) const { return loc2distvert[pi-PointIndex::BASE]; } - auto & L2G (PointIndex pi) { return glob_vert[pi-PointIndex::BASE]; } - auto L2G (PointIndex pi) const { return glob_vert[pi-PointIndex::BASE]; } [[deprecated("Use GetDistantProcs(..).Contains instead!")]] From a8062a6f363ac9bd4c59868b805294034684f085 Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Tue, 1 Sep 2020 11:59:37 +0200 Subject: [PATCH 153/384] fix missing initial value for offset in HashArchive --- libsrc/core/archive.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsrc/core/archive.hpp b/libsrc/core/archive.hpp index dc381a4a..2a006693 100644 --- a/libsrc/core/archive.hpp +++ b/libsrc/core/archive.hpp @@ -918,7 +918,7 @@ namespace ngcore { size_t hash_value; char* h; - int offset; + int offset = 0; public: HashArchive() : Archive(true) { h = (char*)&hash_value; } From a8a0b9d50bc24d51fd249be301dcae78f482163b Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Tue, 1 Sep 2020 17:36:08 +0200 Subject: [PATCH 154/384] fix bc/mat names in CGNS reader --- libsrc/interface/rw_cgns.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/libsrc/interface/rw_cgns.cpp b/libsrc/interface/rw_cgns.cpp index 53532883..0ba38844 100644 --- a/libsrc/interface/rw_cgns.cpp +++ b/libsrc/interface/rw_cgns.cpp @@ -590,6 +590,13 @@ namespace netgen::cg } } } + + mesh.GetRegionNamesCD(2).SetSize(index_1d); + mesh.GetRegionNamesCD(1).SetSize(index_2d); + mesh.GetRegionNamesCD(0).SetSize(index_3d); + mesh.GetRegionNamesCD(2) = nullptr; + mesh.GetRegionNamesCD(1) = nullptr; + mesh.GetRegionNamesCD(0) = nullptr; } void SetNames( Mesh & mesh ) From 2f18c2b1f72660174ab5d7643d1babc8d5826533 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Tue, 1 Sep 2020 20:50:03 +0200 Subject: [PATCH 155/384] Mesh::Mirror() --- libsrc/meshing/meshclass.cpp | 86 ++++++++++++++++++++++++++++++++++ libsrc/meshing/meshclass.hpp | 1 + libsrc/meshing/python_mesh.cpp | 1 + 3 files changed, 88 insertions(+) diff --git a/libsrc/meshing/meshclass.cpp b/libsrc/meshing/meshclass.cpp index 6bcd6e0c..d84db555 100644 --- a/libsrc/meshing/meshclass.cpp +++ b/libsrc/meshing/meshclass.cpp @@ -6860,4 +6860,90 @@ namespace netgen if (surfelementht) surfelementht->PrintMemInfo (cout); } + + shared_ptr Mesh :: Mirror ( netgen::Point<3> p_plane, Vec<3> n_plane ) + { + Mesh & m = *this; + auto nm_ = make_shared(); + Mesh & nm = *nm_; + nm = m; + + Point3d pmin, pmax; + GetBox(pmin, pmax); + auto v = pmax-pmin; + double eps = v.Length()*1e-8; + + auto onPlane = [&] (const MeshPoint & p) -> bool + { + auto v = p_plane-p; + auto l = v.Length(); + if(l PointIndex + { + auto & p = m[pi]; + + auto v = p_plane-p; + auto l = v.Length(); + if(l point_map; + point_map.SetSize(GetNP()); + point_map = -1; + + for(auto pi : Range(points)) + point_map[pi] = mirror(pi); + + for(auto & el : VolumeElements()) + { + auto nel = el; + for(auto i : Range(el.GetNP())) + nel[i] = point_map[el[i]]; + nm.AddVolumeElement(nel); + } + + for (auto ei : Range(SurfaceElements())) + { + auto & el = m[ei]; + auto nel = el; + for(auto i : Range(el.GetNP())) + nel[i] = point_map[el[i]]; + + if(!(nel==el)) + nm.AddSurfaceElement(nel); + } + + for (auto ei : Range(LineSegments())) + { + auto & el = LineSegments()[ei]; + auto nel = el; + bool is_same = true; + + for(auto i : Range(el.GetNP())) + { + auto pi = el[i]; + nel[i] = point_map[pi]; + if(point_map[pi]!=pi) + is_same = false; + } + + if(!is_same) + nm.AddSegment(nel); + } + + return nm_; + } + } diff --git a/libsrc/meshing/meshclass.hpp b/libsrc/meshing/meshclass.hpp index 5139cb8c..59ed7b85 100644 --- a/libsrc/meshing/meshclass.hpp +++ b/libsrc/meshing/meshclass.hpp @@ -923,6 +923,7 @@ namespace netgen NgArray & segment_weights){ } #endif + shared_ptr Mirror( netgen::Point<3> p, Vec<3> n ); }; diff --git a/libsrc/meshing/python_mesh.cpp b/libsrc/meshing/python_mesh.cpp index 07856c1c..5b2ea5c1 100644 --- a/libsrc/meshing/python_mesh.cpp +++ b/libsrc/meshing/python_mesh.cpp @@ -1150,6 +1150,7 @@ grow_edges : bool = False }) .def ("CalcTotalBadness", &Mesh::CalcTotalBad) .def ("GetQualityHistogram", &Mesh::GetQualityHistogram) + .def("Mirror", &Mesh::Mirror); ; m.def("ImportMesh", [](const string& filename) From 585a2e086c274ae3f603b1c75801c0110bf4fe2a Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Tue, 1 Sep 2020 22:55:10 +0200 Subject: [PATCH 156/384] read cgns - set domin/domout in FaceDescriptor --- libsrc/interface/rw_cgns.cpp | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/libsrc/interface/rw_cgns.cpp b/libsrc/interface/rw_cgns.cpp index 0ba38844..a21fdca9 100644 --- a/libsrc/interface/rw_cgns.cpp +++ b/libsrc/interface/rw_cgns.cpp @@ -615,7 +615,10 @@ namespace netgen::cg mesh.SetCD2Name(first_index_1d + i +1, names_1d[i]); for (auto i : Range(names_2d.Size())) + { mesh.SetBCName(first_index_2d + i, names_2d[i]); + mesh.GetFaceDescriptor(first_index_2d + i +1).SetDomainIn(first_index_3d+1); + } for (auto i : Range(names_3d.Size())) mesh.SetMaterial(first_index_3d + i +1, names_3d[i]); @@ -667,6 +670,31 @@ namespace netgen for (auto & zone : zones) zone->SetNames(mesh); + + mesh.UpdateTopology(); + const auto & topo = mesh.GetTopology(); + + for (auto sei : Range(mesh.SurfaceElements())) + { + int ei0, ei1; + topo.GetSurface2VolumeElement (sei, ei0, ei1); + auto si = mesh.SurfaceElement(sei).GetIndex(); + auto & fd = mesh.GetFaceDescriptor(si); + + if(ei0>0) + { + int i0 = mesh.VolumeElement(ei0).GetIndex(); + if(fd.DomainIn()!=i0) + fd.SetDomainOut(i0); + } + + if(ei1>0) + { + int i1 = mesh.VolumeElement(ei1).GetIndex(); + if(fd.DomainIn()!=i1) + fd.SetDomainOut(i1); + } + } return fn; } From e3f95528e0ec61717d5d51514dcc98ce9634800b Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Thu, 3 Sep 2020 11:06:34 +0200 Subject: [PATCH 157/384] throw if IdentifyBoundaries mapped point is outside of mesh --- libsrc/meshing/meshclass.cpp | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/libsrc/meshing/meshclass.cpp b/libsrc/meshing/meshclass.cpp index d84db555..401cd20f 100644 --- a/libsrc/meshing/meshclass.cpp +++ b/libsrc/meshing/meshclass.cpp @@ -6261,22 +6261,31 @@ namespace netgen auto mapped_pt = mapping(pt); auto other_nr = GetElementOfPoint(mapped_pt, lami, true); int index = -1; - auto other_el = VolumeElement(other_nr); - for(auto i : Range(other_el.PNums().Size())) - if((mapped_pt - (*this)[other_el.PNums()[i]]).Length() < pointTolerance) - { - index = i; - break; - } - if(index == -1) + if(other_nr != 0) + { + auto other_el = VolumeElement(other_nr); + for(auto i : Range(other_el.PNums().Size())) + if((mapped_pt - (*this)[other_el.PNums()[i]]).Length() < pointTolerance) + { + index = i; + break; + } + if(index == -1) + { + cout << "point coordinates = " << pt << endl; + cout << "mapped coordinates = " << mapped_pt << endl; + throw Exception("Did not find mapped point with nr " + ToString(pi) + ", are you sure your mesh is periodic?"); + } + auto other_pi = other_el.PNums()[index]; + identified_points.insert(pi); + ident->Add(pi, other_pi, nr); + } + else { cout << "point coordinates = " << pt << endl; cout << "mapped coordinates = " << mapped_pt << endl; - throw Exception("Did not find mapped point with nr " + ToString(pi) + ", are you sure your mesh is periodic?"); + throw Exception("Mapped point with nr " + ToString(pi) + " is outside of mesh, are you sure your mesh is periodic?"); } - auto other_pi = other_el.PNums()[index]; - identified_points.insert(pi); - ident->Add(pi, other_pi, nr); } } return nr; From a45cbd6f84eb4cc87760db76257f3580b7fd18d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20Sch=C3=B6berl?= Date: Fri, 4 Sep 2020 14:47:49 +0200 Subject: [PATCH 158/384] parallel pickling per default on --- libsrc/core/python_ngcore.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsrc/core/python_ngcore.cpp b/libsrc/core/python_ngcore.cpp index cf50ace4..cb8c94d4 100644 --- a/libsrc/core/python_ngcore.cpp +++ b/libsrc/core/python_ngcore.cpp @@ -8,7 +8,7 @@ using std::string; namespace ngcore { bool ngcore_have_numpy = false; - bool parallel_pickling = false; + bool parallel_pickling = true; void SetFlag(Flags &flags, string s, py::object value) { From 218c4a531b79ce9aa471fff41d825e92a232d912 Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Mon, 7 Sep 2020 15:19:53 +0200 Subject: [PATCH 159/384] fix uninizialized area and maybe deleted value being appended pout3d may be deleted when array resizes, so copy it --- libsrc/meshing/meshclass.hpp | 2 +- libsrc/meshing/meshing2.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libsrc/meshing/meshclass.hpp b/libsrc/meshing/meshclass.hpp index 59ed7b85..e3b45b9b 100644 --- a/libsrc/meshing/meshclass.hpp +++ b/libsrc/meshing/meshclass.hpp @@ -797,7 +797,7 @@ namespace netgen double area; public: CSurfaceArea (const Mesh & amesh) - : mesh(amesh), valid(false) { ; } + : mesh(amesh), valid(false), area(0.) { ; } void Add (const Element2d & sel) { diff --git a/libsrc/meshing/meshing2.cpp b/libsrc/meshing/meshing2.cpp index bda90593..edf4770d 100644 --- a/libsrc/meshing/meshing2.cpp +++ b/libsrc/meshing/meshing2.cpp @@ -675,7 +675,7 @@ namespace netgen plainpoints.Append (newpout); - const auto& pout3d = locpoints.Get(pouti); + auto pout3d = locpoints.Get(pouti); locpoints.Append (pout3d); plainzones.Append (0); From 5c2089ed96eccde31a96f78c483fd856accccd3a Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Mon, 7 Sep 2020 15:50:48 +0200 Subject: [PATCH 160/384] push git tags to sourceforge --- .gitlab-ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index c50d4eb0..a862660a 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -15,8 +15,8 @@ push_github_sourceforge: - git remote update - git checkout master - git pull origin master - - git push sourceforge master - - git push github master + - git push sourceforge master --tags + - git push github master --tags only: - master From b2b8a156119330c0f2c3482ce8f87bbcad1acad9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20Sch=C3=B6berl?= Date: Tue, 8 Sep 2020 23:00:03 +0200 Subject: [PATCH 161/384] Array copy only if type is assignable --- libsrc/core/array.hpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/libsrc/core/array.hpp b/libsrc/core/array.hpp index 28868d91..c83c4431 100644 --- a/libsrc/core/array.hpp +++ b/libsrc/core/array.hpp @@ -940,11 +940,16 @@ namespace ngcore /// array copy NETGEN_INLINE Array & operator= (const Array & a2) { - SetSize0 (); - SetSize (a2.Size()); - for (size_t i = 0; i < size; i++) - data[i] = a2.data[i]; - return *this; + if constexpr (std::is_assignable::value) + { + SetSize0 (); + SetSize (a2.Size()); + for (size_t i = 0; i < size; i++) + data[i] = a2.data[i]; + return *this; + } + else + throw Exception(std::string("cannot copy Array of type ") + typeid(T).name()); } /// steal array From 98697959dd6694ba370528b1a671c6058454ca96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20Sch=C3=B6berl?= Date: Wed, 9 Sep 2020 06:31:03 +0200 Subject: [PATCH 162/384] check for copy_assignable --- libsrc/core/array.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libsrc/core/array.hpp b/libsrc/core/array.hpp index c83c4431..f91c4f7e 100644 --- a/libsrc/core/array.hpp +++ b/libsrc/core/array.hpp @@ -940,7 +940,7 @@ namespace ngcore /// array copy NETGEN_INLINE Array & operator= (const Array & a2) { - if constexpr (std::is_assignable::value) + if constexpr (std::is_copy_assignable::value) { SetSize0 (); SetSize (a2.Size()); @@ -952,6 +952,7 @@ namespace ngcore throw Exception(std::string("cannot copy Array of type ") + typeid(T).name()); } + /// steal array NETGEN_INLINE Array & operator= (Array && a2) { From 65761e77680c018e9720e187dd8c3363494a5e27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20Sch=C3=B6berl?= Date: Wed, 9 Sep 2020 07:03:12 +0200 Subject: [PATCH 163/384] check copy_assignable also in copy-constructor --- libsrc/core/array.hpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/libsrc/core/array.hpp b/libsrc/core/array.hpp index f91c4f7e..acd1981c 100644 --- a/libsrc/core/array.hpp +++ b/libsrc/core/array.hpp @@ -712,10 +712,15 @@ namespace ngcore NETGEN_INLINE explicit Array (const Array & a2) : FlatArray (a2.Size(), a2.Size() ? new T[a2.Size()] : nullptr) { - allocsize = size; - mem_to_delete = data; - for (size_t i = 0; i < size; i++) - data[i] = a2.data[i]; + if constexpr (std::is_copy_assignable::value) + { + allocsize = size; + mem_to_delete = data; + for (size_t i = 0; i < size; i++) + data[i] = a2.data[i]; + } + else + throw Exception(std::string("cannot copy-construct Array of type ") + typeid(T).name()); } From 52b372718c07a8fcd47ff339d82df3b6bde96daa Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Wed, 9 Sep 2020 11:33:06 +0200 Subject: [PATCH 164/384] generate netgen_config.hpp containing all cmake options --- CMakeLists.txt | 2 +- cmake/generate_version_file.cmake | 29 +++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5a003954..c756c441 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -413,7 +413,7 @@ if(USE_CGNS) endif(NOT WIN32 AND NOT APPLE) endif(USE_CGNS) -install(FILES ${CMAKE_CURRENT_BINARY_DIR}/netgen_version.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(libsrc) add_subdirectory(ng) diff --git a/cmake/generate_version_file.cmake b/cmake/generate_version_file.cmake index de709298..b8df93c2 100644 --- a/cmake/generate_version_file.cmake +++ b/cmake/generate_version_file.cmake @@ -61,3 +61,32 @@ else() file(WRITE ${BDIR}/netgen_version.hpp ${new_version_file_string}) endif() +file(GENERATE OUTPUT netgen_config.hpp CONTENT +"\ +#ifndef NETGEN_CONFIG_HPP_INCLUDED___ +#define NETGEN_CONFIG_HPP_INCLUDED___ + +#define NETGEN_USE_NATIVE_ARCH $ +#define NETGEN_USE_GUI $ +#define NETGEN_USE_PYTHON $ +#define NETGEN_USE_MPI $ +#define NETGEN_USE_MPI4PY $ +#define NETGEN_USE_OCC $ +#define NETGEN_USE_JPEG $ +#define NETGEN_USE_MPEG $ +#define NETGEN_USE_CGNS $ +#define NETGEN_USE_NUMA $ +#define NETGEN_INTEL_MIC $ +#define NETGEN_INSTALL_PROFILES $ +#define NETGEN_USE_CCACHE $ +#define NETGEN_USE_INTERNAL_TCL $ +#define NETGEN_ENABLE_UNIT_TESTS $ +#define NETGEN_ENABLE_CPP_CORE_GUIDELINES_CHECK $ +#define NETGEN_USE_SPDLOG $ +#define NETGEN_DEBUG_LOG $ +#define NETGEN_CHECK_RANGE $ +#define NETGEN_BUILD_STUB_FILES $ +#define NETGEN_BUILD_FOR_CONDA $ + +#endif // NETGEN_CONFIG_HPP_INCLUDED___ +") From 4502c464a48d391ab5a515e4761b9bee54ea30b0 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Wed, 9 Sep 2020 11:43:55 +0200 Subject: [PATCH 165/384] fix incopengl.hpp include on Windows (windows.h needed) --- libsrc/include/incopengl.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libsrc/include/incopengl.hpp b/libsrc/include/incopengl.hpp index 8cff36af..9ce0d413 100644 --- a/libsrc/include/incopengl.hpp +++ b/libsrc/include/incopengl.hpp @@ -2,6 +2,7 @@ #define INCOPENGL_HPP___ #define GL_GLEXT_PROTOTYPES +#include #include # if defined(TOGL_AGL) || defined(TOGL_AGL_CLASSIC) || defined(TOGL_NSOPENGL) From cb610b9b04961e9753879b0328ca6fd08022142e Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Wed, 9 Sep 2020 11:53:05 +0200 Subject: [PATCH 166/384] NETGEN_CHECK_RANGE -> NETGEN_USE_CHECK_RANGE in netgen_config.hpp (macro name already used) --- cmake/generate_version_file.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/generate_version_file.cmake b/cmake/generate_version_file.cmake index b8df93c2..92390efc 100644 --- a/cmake/generate_version_file.cmake +++ b/cmake/generate_version_file.cmake @@ -84,7 +84,7 @@ file(GENERATE OUTPUT netgen_config.hpp CONTENT #define NETGEN_ENABLE_CPP_CORE_GUIDELINES_CHECK $ #define NETGEN_USE_SPDLOG $ #define NETGEN_DEBUG_LOG $ -#define NETGEN_CHECK_RANGE $ +#define NETGEN_USE_CHECK_RANGE $ #define NETGEN_BUILD_STUB_FILES $ #define NETGEN_BUILD_FOR_CONDA $ From 00ce0a27697e6886b0b9c630bd2f79ea8765fb54 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Wed, 9 Sep 2020 11:58:38 +0200 Subject: [PATCH 167/384] DLL_HEADER for UserVisualizationObject functions --- libsrc/visualization/vssolution.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libsrc/visualization/vssolution.cpp b/libsrc/visualization/vssolution.cpp index c39156ea..25decb88 100644 --- a/libsrc/visualization/vssolution.cpp +++ b/libsrc/visualization/vssolution.cpp @@ -24,12 +24,12 @@ namespace netgen extern VisualSceneMesh vsmesh; - void AddUserVisualizationObject (UserVisualizationObject * vis) + DLL_HEADER void AddUserVisualizationObject (UserVisualizationObject * vis) { // vssolution.AddUserVisualizationObject (vis); GetVSSolution().AddUserVisualizationObject (vis); } - void DeleteUserVisualizationObject (UserVisualizationObject * vis) + DLL_HEADER void DeleteUserVisualizationObject (UserVisualizationObject * vis) { // vssolution.AddUserVisualizationObject (vis); GetVSSolution().DeleteUserVisualizationObject (vis); From caca0d4d08bcd159210fbf6fffb6a8048cc1ddc4 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Wed, 9 Sep 2020 13:04:21 +0200 Subject: [PATCH 168/384] Use __APPLE__ instead of TOGL_NSOPENGL --- libsrc/include/incopengl.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsrc/include/incopengl.hpp b/libsrc/include/incopengl.hpp index 9ce0d413..1f42f12f 100644 --- a/libsrc/include/incopengl.hpp +++ b/libsrc/include/incopengl.hpp @@ -5,7 +5,7 @@ #include #include -# if defined(TOGL_AGL) || defined(TOGL_AGL_CLASSIC) || defined(TOGL_NSOPENGL) +# ifdef __APPLE__ #define GL_SILENCE_DEPRECATION #define GL_DO_NOT_WARN_IF_MULTI_GL_VERSION_HEADERS_INCLUDED # include From 24782ccc0477b429a282041fb814b9e1609136d3 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Wed, 9 Sep 2020 17:07:36 +0200 Subject: [PATCH 169/384] CSG2d Rectangle() - individual bc names --- libsrc/geom2d/python_geom2d.cpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/libsrc/geom2d/python_geom2d.cpp b/libsrc/geom2d/python_geom2d.cpp index aa3b77c4..b5a07a1f 100644 --- a/libsrc/geom2d/python_geom2d.cpp +++ b/libsrc/geom2d/python_geom2d.cpp @@ -9,6 +9,7 @@ #include using namespace netgen; +using namespace pybind11::literals; namespace netgen { @@ -426,9 +427,18 @@ DLL_HEADER void ExportGeom2d(py::module &m) ; - m.def("Rectangle", [](Point<2> pmin, Point<2> pmax, string mat, string bc) - { return Rectangle(pmin, pmax, mat, bc); }, - py::arg("pmin"), py::arg("pmax"), py::arg("mat")=MAT_DEFAULT, py::arg("bc")=BC_DEFAULT + m.def("Rectangle", [](Point<2> p0, Point<2> p1, string mat, string bc, optional bottom, optional right, optional top, optional left) -> Solid2d + { + using P = Point<2>; + return { { + p0, bottom ? *bottom : bc, + P{p1[0],p0[1]}, right ? *right : bc, + p1, top ? *top : bc, + P{p0[0],p1[1]}, left ? *left : bc, + }, mat}; + }, + "pmin"_a, "pmax"_a, "mat"_a=MAT_DEFAULT, "bc"_a=BC_DEFAULT, + "bottom"_a=nullopt, "right"_a=nullopt, "top"_a=nullopt, "left"_a=nullopt ); m.def("Circle", Circle, py::arg("center"), py::arg("radius"), py::arg("mat")=MAT_DEFAULT, py::arg("bc")=BC_DEFAULT); From f6c94035c5bef49102d05d2b55faa3ae3464fbbc Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Fri, 11 Sep 2020 09:05:53 +0200 Subject: [PATCH 170/384] SetDomainQuadMeshing for 2d geometry --- libsrc/geom2d/geometry2d.hpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/libsrc/geom2d/geometry2d.hpp b/libsrc/geom2d/geometry2d.hpp index c7f59824..e71d17d8 100644 --- a/libsrc/geom2d/geometry2d.hpp +++ b/libsrc/geom2d/geometry2d.hpp @@ -215,6 +215,20 @@ namespace netgen if ( quadmeshing.Size() ) return quadmeshing[domnr-1]; else return false; } + void SetDomainQuadMeshing ( int domnr, bool quad_meshing ) + { + auto oldsize = quadmeshing.Size(); + + if ( oldsize=domnr ) return tensormeshing[domnr-1]; From 86fe7f3be7af481854cb648f708896aa94631e2d Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Fri, 4 Sep 2020 13:15:13 +0200 Subject: [PATCH 171/384] csg2d - optimize GenerateSplineGeometry() --- libsrc/geom2d/csg2d.cpp | 52 ++++++++++++++++++++++++++++++----------- libsrc/geom2d/csg2d.hpp | 4 +++- 2 files changed, 41 insertions(+), 15 deletions(-) diff --git a/libsrc/geom2d/csg2d.cpp b/libsrc/geom2d/csg2d.cpp index c3e0c950..05417d5c 100644 --- a/libsrc/geom2d/csg2d.cpp +++ b/libsrc/geom2d/csg2d.cpp @@ -1278,11 +1278,11 @@ Solid2d Circle(Point<2> center, double r, string name, string bc) return Solid2d( { p[0], cp[0], p[1], cp[1], p[2], cp[2], p[3], cp[3] }, name, bc ); } -Solid2d AddIntersectionPoints ( Solid2d s1, Solid2d s2 ) +void AddIntersectionPoints ( Solid2d & s1, Solid2d & s2 ) { ComputeIntersections(s1, s2); RemoveDuplicates(s1); - return s1; + RemoveDuplicates(s2); } Solid2d ClipSolids ( Solid2d s1, Solid2d s2, bool intersect) @@ -1517,6 +1517,16 @@ bool Solid2d :: IsRightInside( const Vertex & p0 ) return IsInside(q); } +netgen::Box<2> Solid2d :: GetBoundingBox() +{ + netgen::Box<2> box(netgen::Box<2>::EMPTY_BOX); + for(auto & poly : polys) + for(auto v : poly.Vertices(ALL)) + box.Add(*v); + + return box; +} + shared_ptr CSG2d :: GenerateSplineGeometry() { static Timer t_intersections("CSG2d - AddIntersections()"); @@ -1541,23 +1551,37 @@ shared_ptr CSG2d :: GenerateSplineGeometry() Array points; // Cut each solid with each other one to add all possible intersection points and have conforming edges from both domains - // TODO: OPTIMIZE!!! - // Idea: Find edges with just one neighbor (either leftdomain or rightdomain unset after the marking below) -> just cut those edges with each other t_intersections.Start(); - for(auto & s1 : solids) - for(auto & s2 : solids) - if(&s1!=&s2) - s1 = AddIntersectionPoints(s1,s2); + + // First build bounding boxes for each solid to skip non-overlapping pairs + netgen::Box<2> box(netgen::Box<2>::EMPTY_BOX); + for(auto i : Range(solids)) + { + auto sbox = solids[i].GetBoundingBox(); + box.Add(sbox.PMin()); + box.Add(sbox.PMax()); + } + + netgen::BoxTree <2, int> solid_tree(box); + + for(auto i : Range(solids)) + solid_tree.Insert(solids[i].GetBoundingBox(), i); + + for(auto i1 : Range(solids)) + { + auto sbox = solids[i1].GetBoundingBox(); + solid_tree.GetFirstIntersecting(sbox.PMin(), sbox.PMax(), [&] (int i2) + { + if(i1 box(netgen::Box<2>::EMPTY_BOX); - for(auto & s : solids) - for(auto & poly : s.polys) - for(auto v : poly.Vertices(ALL)) - box.Add(*v); - netgen::BoxTree <2, int> ptree(box); auto getPoint = [&](Point<2> p ) diff --git a/libsrc/geom2d/csg2d.hpp b/libsrc/geom2d/csg2d.hpp index 4fe00fe0..cb77143e 100644 --- a/libsrc/geom2d/csg2d.hpp +++ b/libsrc/geom2d/csg2d.hpp @@ -631,6 +631,8 @@ struct Solid2d name = mat; return *this; } + + netgen::Box<2> GetBoundingBox(); }; @@ -651,7 +653,7 @@ class CSG2d Solid2d Circle( Point<2> center, double r, string name="", string bc=""); Solid2d Rectangle( Point<2> p0, Point<2> p1, string mat=MAT_DEFAULT, string bc=BC_DEFAULT ); -Solid2d AddIntersectionPoints ( Solid2d s1, Solid2d s2 ); +void AddIntersectionPoints ( Solid2d & s1, Solid2d & s2 ); Solid2d ClipSolids ( Solid2d s1, Solid2d s2, bool intersect=true ); } From c7af26771e5fa1fb43b64577b15cff8cd251992f Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Fri, 11 Sep 2020 16:54:25 +0200 Subject: [PATCH 172/384] fix bug in BitArray== --- libsrc/core/bitarray.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsrc/core/bitarray.cpp b/libsrc/core/bitarray.cpp index 2523ce5f..bc923ef1 100644 --- a/libsrc/core/bitarray.cpp +++ b/libsrc/core/bitarray.cpp @@ -91,7 +91,7 @@ namespace ngcore if(data[i] != other.data[i]) return false; for(auto i : Range(size%CHAR_BIT)) - if(Test(i + size * (size/CHAR_BIT)) != other.Test(i + size * (size/CHAR_BIT))) + if(Test(i + CHAR_BIT * (size/CHAR_BIT)) != other.Test(i + CHAR_BIT * (size/CHAR_BIT))) return false; return true; } From 10a9decfd25460d9a639460ba28f58299340029e Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Mon, 14 Sep 2020 12:13:16 +0200 Subject: [PATCH 173/384] csg2d - separate bc numbers --- libsrc/geom2d/csg2d.cpp | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/libsrc/geom2d/csg2d.cpp b/libsrc/geom2d/csg2d.cpp index 05417d5c..0dddf074 100644 --- a/libsrc/geom2d/csg2d.cpp +++ b/libsrc/geom2d/csg2d.cpp @@ -1547,7 +1547,7 @@ shared_ptr CSG2d :: GenerateSplineGeometry() auto geo = std::make_shared(); std::map, Seg> seg_map; - std::map bcmap; + Array bcnames; Array points; // Cut each solid with each other one to add all possible intersection points and have conforming edges from both domains @@ -1621,6 +1621,7 @@ shared_ptr CSG2d :: GenerateSplineGeometry() // Generate segments from polygon edges and find left/right domain of each segment int dom = 0; + int bc = 1; for(auto & s : solids) { dom++; @@ -1660,11 +1661,11 @@ shared_ptr CSG2d :: GenerateSplineGeometry() ls.p2 = pi2; ls.weight = weight; - if(bcmap.count(p0.info.bc)==0) - bcmap[p0.info.bc] = bcmap.size()+1; - if(ls.bc==0 || p0.info.bc != BC_DEFAULT) - ls.bc = bcmap[p0.info.bc]; + { + ls.bc = bc++; + bcnames.Append(p0.info.bc); + } ls.maxh = min(ls.maxh, p0.info.maxh); @@ -1685,10 +1686,8 @@ shared_ptr CSG2d :: GenerateSplineGeometry() dom--; // degenerated solid, use same domain index again } - for(auto & [name, bc] : bcmap) - { - geo->SetBCName(bc, name); - } + for(auto bc : Range(bcnames)) + geo->SetBCName(bc+1, bcnames[bc]); for(auto const &m : seg_map) { From 2763285b4620f61b6e4876fafc414a07a46dc741 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Tue, 15 Sep 2020 15:48:49 +0200 Subject: [PATCH 174/384] csg2d - fix tutorial --- libsrc/geom2d/csg2d.cpp | 31 +++++++++++++++++++--- py_tutorials/csg2d.py | 57 ++++++++++++++++------------------------- 2 files changed, 49 insertions(+), 39 deletions(-) diff --git a/libsrc/geom2d/csg2d.cpp b/libsrc/geom2d/csg2d.cpp index 0dddf074..e945c586 100644 --- a/libsrc/geom2d/csg2d.cpp +++ b/libsrc/geom2d/csg2d.cpp @@ -345,12 +345,35 @@ bool IsOverlapping( Spline p, Spline s, double & alpha, double & beta, Intersect // Check if s.p0 lies on p and vice versa, also check if tangents are in same direction (TODO: TEST) // If so, assume overlapping splines // TODO: Better checks! False positives could happen here! - IntersectSplineSegment1( p, s.StartPI(), p_mid, lam0, alpha, true ); - IntersectSplineSegment1( s, p.StartPI(), s_mid, lam1, beta, true ); + if(Dist(s.StartPI(), p.StartPI()) Date: Tue, 15 Sep 2020 23:15:50 +0200 Subject: [PATCH 175/384] check if mpi is initialized --- libsrc/core/mpi_wrapper.hpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/libsrc/core/mpi_wrapper.hpp b/libsrc/core/mpi_wrapper.hpp index bdf2505b..2e046d18 100644 --- a/libsrc/core/mpi_wrapper.hpp +++ b/libsrc/core/mpi_wrapper.hpp @@ -67,6 +67,17 @@ namespace ngcore NgMPI_Comm (MPI_Comm _comm, bool owns = false) : comm(_comm), valid_comm(true) { + int flag; + MPI_Initialized (&flag); + if (!flag) + { + valid_comm = false; + refcount = nullptr; + rank = 0; + size = 1; + return; + } + if (!owns) refcount = nullptr; else From 283db5c6374b8524c54ff65e0165275c0611c904 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20Sch=C3=B6berl?= Date: Sat, 19 Sep 2020 09:43:00 +0200 Subject: [PATCH 176/384] trange bracket with size_t for T_Range --- libsrc/core/array.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsrc/core/array.hpp b/libsrc/core/array.hpp index acd1981c..864fd454 100644 --- a/libsrc/core/array.hpp +++ b/libsrc/core/array.hpp @@ -268,7 +268,7 @@ namespace ngcore NETGEN_INLINE T & First() { return first; } NETGEN_INLINE T & Next() { return next; } NETGEN_INLINE auto Size() const { return next-first; } - NETGEN_INLINE T operator[] (T i) const { return first+i; } + NETGEN_INLINE T operator[] (size_t i) const { return first+i; } NETGEN_INLINE bool Contains (T i) const { return ((i >= first) && (i < next)); } NETGEN_INLINE T_Range Modify(int inc_beg, int inc_end) const { return T_Range(first+inc_beg, next+inc_end); } From 1666155d25de9bf0222f9a1e3fde350909b62aff Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Sat, 19 Sep 2020 17:39:03 +0200 Subject: [PATCH 177/384] add range adaptors (filter, transform) --- libsrc/core/CMakeLists.txt | 2 +- libsrc/core/ranges.hpp | 109 +++++++++++++++++++++++++++++++++++++ tests/catch/CMakeLists.txt | 1 + tests/catch/ranges.cpp | 18 ++++++ 4 files changed, 129 insertions(+), 1 deletion(-) create mode 100644 libsrc/core/ranges.hpp create mode 100644 tests/catch/ranges.cpp diff --git a/libsrc/core/CMakeLists.txt b/libsrc/core/CMakeLists.txt index 16c43a82..a2873ed9 100644 --- a/libsrc/core/CMakeLists.txt +++ b/libsrc/core/CMakeLists.txt @@ -65,7 +65,7 @@ target_link_libraries(ngcore PUBLIC netgen_mpi PRIVATE netgen_python ${CMAKE_THR install(FILES ngcore.hpp archive.hpp type_traits.hpp version.hpp ngcore_api.hpp logging.hpp exception.hpp symboltable.hpp paje_trace.hpp utils.hpp profiler.hpp mpi_wrapper.hpp array.hpp taskmanager.hpp concurrentqueue.h localheap.hpp python_ngcore.hpp flags.hpp - xbool.hpp signal.hpp bitarray.hpp table.hpp hashtable.hpp + xbool.hpp signal.hpp bitarray.hpp table.hpp hashtable.hpp ranges.hpp DESTINATION ${NG_INSTALL_DIR_INCLUDE}/core COMPONENT netgen_devel) if(ENABLE_CPP_CORE_GUIDELINES_CHECK) diff --git a/libsrc/core/ranges.hpp b/libsrc/core/ranges.hpp new file mode 100644 index 00000000..658ee3d0 --- /dev/null +++ b/libsrc/core/ranges.hpp @@ -0,0 +1,109 @@ +#ifndef NETGEN_CORE_RANGES_HPP +#define NETGEN_CORE_RANGES_HPP + +#include + +namespace ngcore +{ + template + class AdapterRange + { + Iterator _begin,_end; + public: + AdapterRange(Iterator abegin, Iterator aend) : _begin(abegin), _end(aend) { ; } + Iterator begin() const { return _begin; } + Iterator end() const { return _end; } + }; + + template + class FilterAdapter + { + FUNC f; + public: + FilterAdapter(FUNC af) : f(af) { ; } + FUNC GetFunction() const { return f; } + }; + + template + class FilterIterator + { + Iterator iter; + Iterator end; + FUNC f; + public: + FilterIterator(FUNC af, Iterator aiter, Iterator aend) + : f(af), iter(aiter), end(aend) + { + while(iter!=end && !f(*iter)) + ++iter; + } + inline FilterIterator& operator ++() + { + ++iter; + while(iter!=end && !f(*iter)) + ++iter; + return *this; + } + + inline bool operator !=(FilterIterator other) + { + return iter != other.iter; + } + + inline bool operator ==(FilterIterator other) + { + return iter == other.iter; + } + + inline decltype(auto) operator *() const + { + return *iter; + } + }; + + template + FilterAdapter filter(FUNC f) { return {f}; } + + template + auto operator |(Range&& range, FilterAdapter adapter) + -> AdapterRange> + { + return {{adapter.GetFunction(),std::begin(range),std::end(range)}, + {adapter.GetFunction(), std::end(range), std::end(range)}}; + } + + template + class TransformIterator + { + FUNC f; + Iterator iter; + public: + TransformIterator(FUNC af, Iterator aiter) : f(af), iter(aiter) { ; } + + TransformIterator& operator++() { ++iter; } + bool operator !=(TransformIterator other) { return iter != other.iter; } + decltype(auto) operator *() const { return f(*iter); } + }; + + template + class TransformAdapter + { + FUNC f; + public: + TransformAdapter(FUNC af) : f(af) { ; } + FUNC GetFunction() const { return f; } + }; + + template + TransformAdapter transform(FUNC f) { return {f}; } + + template + auto operator |(Range&& range, TransformAdapter adapter) + -> AdapterRange> + { + return {{adapter.GetFunction(), std::begin(range)}, + {adapter.GetFunction(),std::end(range)}}; + } +} // namespace ngcore + +#endif // NETGEN_CORE_RANGES_HPP diff --git a/tests/catch/CMakeLists.txt b/tests/catch/CMakeLists.txt index c3a6525d..12a665df 100644 --- a/tests/catch/CMakeLists.txt +++ b/tests/catch/CMakeLists.txt @@ -27,6 +27,7 @@ endmacro() add_unit_test(archive archive.cpp) add_unit_test(array array.cpp) +add_unit_test(ranges ranges.cpp) add_unit_test(symboltable symboltable.cpp) add_unit_test(utils utils.cpp) add_unit_test(version version.cpp) diff --git a/tests/catch/ranges.cpp b/tests/catch/ranges.cpp new file mode 100644 index 00000000..b4559de0 --- /dev/null +++ b/tests/catch/ranges.cpp @@ -0,0 +1,18 @@ + +#include "catch.hpp" + +#include +#include + +using namespace ngcore; + +TEST_CASE("ranges") +{ + Array a { 3, -1, 10, -5 }; + Array positive { 3, 10 }; + int i = 0; + for(auto pos_val : a | filter([](auto val) { return val >= 0; })) + { + CHECK(pos_val == positive[i++]); + } +} From b124b7bd06180c5816229e67e72b81546cf63c2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20Sch=C3=B6berl?= Date: Mon, 21 Sep 2020 07:49:56 +0200 Subject: [PATCH 178/384] keep global vertex enumeration on coarse grid --- libsrc/meshing/parallelmesh.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsrc/meshing/parallelmesh.cpp b/libsrc/meshing/parallelmesh.cpp index 8f060a1b..e2c5aed2 100644 --- a/libsrc/meshing/parallelmesh.cpp +++ b/libsrc/meshing/parallelmesh.cpp @@ -1028,7 +1028,7 @@ namespace netgen } } - paralleltop -> SetNV_Loc2Glob (0); + // paralleltop -> SetNV_Loc2Glob (0); paralleltop -> EnumeratePointsGlobally(); /** Recv bc-names **/ ArrayMem nnames{0,0,0,0}; From 0852a20fffb4220fcb4ada9dd804e0456f764a73 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Thu, 24 Sep 2020 16:58:59 +0200 Subject: [PATCH 179/384] some DLL_HEADER --- libsrc/geom2d/csg2d.hpp | 30 +++++++++++++++--------------- libsrc/geom2d/geometry2d.hpp | 4 ++-- libsrc/gprim/geomtest3d.hpp | 2 +- libsrc/gprim/spline.hpp | 12 ++++++------ 4 files changed, 24 insertions(+), 24 deletions(-) diff --git a/libsrc/geom2d/csg2d.hpp b/libsrc/geom2d/csg2d.hpp index cb77143e..eeb1a75b 100644 --- a/libsrc/geom2d/csg2d.hpp +++ b/libsrc/geom2d/csg2d.hpp @@ -111,7 +111,7 @@ struct Vertex : Point<2> optional spline = nullopt; EdgeInfo info; - Vertex * Insert(Point<2> p, double lam = -1.0); + DLL_HEADER Vertex * Insert(Point<2> p, double lam = -1.0); void Link( Vertex * v ) { @@ -562,16 +562,16 @@ struct Solid2d Solid2d() = default; Solid2d(string name_) : name(name_) {} - Solid2d(const Array, EdgeInfo>> & points, string name_=MAT_DEFAULT, string bc_=BC_DEFAULT); + DLL_HEADER Solid2d(const Array, EdgeInfo>> & points, string name_=MAT_DEFAULT, string bc_=BC_DEFAULT); - Solid2d operator+(const Solid2d & other) const; - Solid2d operator*(const Solid2d & other) const; - Solid2d operator-(const Solid2d & other) const; + DLL_HEADER Solid2d operator+(const Solid2d & other) const; + DLL_HEADER Solid2d operator*(const Solid2d & other) const; + DLL_HEADER Solid2d operator-(const Solid2d & other) const; - Solid2d& operator=(const Solid2d & other) = default; - Solid2d& operator+=(const Solid2d & other); - Solid2d& operator*=(const Solid2d & other); - Solid2d& operator-=(const Solid2d & other); + DLL_HEADER Solid2d& operator=(const Solid2d & other) = default; + DLL_HEADER Solid2d& operator+=(const Solid2d & other); + DLL_HEADER Solid2d& operator*=(const Solid2d & other); + DLL_HEADER Solid2d& operator-=(const Solid2d & other); void Append( const Loop & poly ) { @@ -646,15 +646,15 @@ class CSG2d solids.Append(s); } - shared_ptr GenerateSplineGeometry(); - shared_ptr GenerateMesh(MeshingParameters & mp); + DLL_HEADER shared_ptr GenerateSplineGeometry(); + DLL_HEADER shared_ptr GenerateMesh(MeshingParameters & mp); }; -Solid2d Circle( Point<2> center, double r, string name="", string bc=""); -Solid2d Rectangle( Point<2> p0, Point<2> p1, string mat=MAT_DEFAULT, string bc=BC_DEFAULT ); +DLL_HEADER Solid2d Circle( Point<2> center, double r, string name="", string bc=""); +DLL_HEADER Solid2d Rectangle( Point<2> p0, Point<2> p1, string mat=MAT_DEFAULT, string bc=BC_DEFAULT ); -void AddIntersectionPoints ( Solid2d & s1, Solid2d & s2 ); -Solid2d ClipSolids ( Solid2d s1, Solid2d s2, bool intersect=true ); +DLL_HEADER void AddIntersectionPoints ( Solid2d & s1, Solid2d & s2 ); +DLL_HEADER Solid2d ClipSolids ( Solid2d s1, Solid2d s2, bool intersect=true ); } #endif // NETGEN_CSG2D_HPP_INCLUDED diff --git a/libsrc/geom2d/geometry2d.hpp b/libsrc/geom2d/geometry2d.hpp index e71d17d8..daab8d12 100644 --- a/libsrc/geom2d/geometry2d.hpp +++ b/libsrc/geom2d/geometry2d.hpp @@ -204,8 +204,8 @@ namespace netgen size_t GetNDomains() const { return materials.Size(); } - void GetMaterial (int domnr, char* & material ); - void SetMaterial (int domnr, const string & material); + DLL_HEADER void GetMaterial (int domnr, char* & material ); + DLL_HEADER void SetMaterial (int domnr, const string & material); double GetDomainMaxh ( const int domnr ); void SetDomainMaxh ( const int domnr, double maxh ); diff --git a/libsrc/gprim/geomtest3d.hpp b/libsrc/gprim/geomtest3d.hpp index c1fb1186..b26c9b41 100644 --- a/libsrc/gprim/geomtest3d.hpp +++ b/libsrc/gprim/geomtest3d.hpp @@ -75,7 +75,7 @@ extern double MinDistLP2 (const Point2d & lp1, const Point2d & lp2, const Point2 extern double MinDistLP2 (const Point3d & lp1, const Point3d & lp2, const Point3d & p); /// Minimal distance of point p to the triangle segment [tp1,tp2,pt3] -extern double MinDistTP2 (const Point3d & tp1, const Point3d & tp2, +DLL_HEADER double MinDistTP2 (const Point3d & tp1, const Point3d & tp2, const Point3d & tp3, const Point3d & p); inline double MinDistTP2 (const Point<2> & tp1, const Point<2> & tp2, diff --git a/libsrc/gprim/spline.hpp b/libsrc/gprim/spline.hpp index b594f85b..94a96f60 100644 --- a/libsrc/gprim/spline.hpp +++ b/libsrc/gprim/spline.hpp @@ -200,9 +200,9 @@ namespace netgen double GetWeight () const { return weight; } void SetWeight (double w) { weight = w; } /// - virtual Point GetPoint (double t) const; + DLL_HEADER virtual Point GetPoint (double t) const; /// - virtual Vec GetTangent (const double t) const; + DLL_HEADER virtual Vec GetTangent (const double t) const; DLL_HEADER virtual void GetDerivatives (const double t, @@ -210,12 +210,12 @@ namespace netgen Vec & first, Vec & second) const; /// - virtual const GeomPoint & StartPI () const { return p1; }; + DLL_HEADER virtual const GeomPoint & StartPI () const { return p1; }; /// - virtual const GeomPoint & EndPI () const { return p3; } + DLL_HEADER virtual const GeomPoint & EndPI () const { return p3; } /// - virtual void GetCoeff (Vector & coeffs) const; - virtual void GetCoeff (Vector & coeffs, Point p0) const; + DLL_HEADER virtual void GetCoeff (Vector & coeffs) const; + DLL_HEADER virtual void GetCoeff (Vector & coeffs, Point p0) const; virtual string GetType(void) const {return "spline3";} From 70347a6d3c1768a6cbd9b41b6a69be3968388176 Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Tue, 29 Sep 2020 18:57:56 +0200 Subject: [PATCH 180/384] tuple implicitly convertible to Pnt and Vec --- libsrc/meshing/python_mesh.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/libsrc/meshing/python_mesh.cpp b/libsrc/meshing/python_mesh.cpp index 5b2ea5c1..c1cbb0c5 100644 --- a/libsrc/meshing/python_mesh.cpp +++ b/libsrc/meshing/python_mesh.cpp @@ -179,6 +179,11 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m) py::class_> (m, "Point3d") .def(py::init()) + .def(py::init([](py::tuple p) + { + return Point<3> { p[0].cast(), p[1].cast(), + p[2].cast() }; + })) .def ("__str__", &ToString>) .def(py::self-py::self) .def(py::self+Vec<3>()) @@ -186,6 +191,8 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m) .def("__getitem__", [](Point<2>& self, int index) { return self[index]; }) ; + py::implicitly_convertible>(); + m.def("Pnt", [](double x, double y, double z) { return global_trafo(Point<3>(x,y,z)); }); m.def("Pnt", [](double x, double y) { return Point<2>(x,y); }); @@ -218,6 +225,11 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m) py::class_> (m, "Vec3d") .def(py::init()) + .def(py::init([](py::tuple v) + { + return Vec<3> { v[0].cast(), v[1].cast(), + v[2].cast() }; + })) .def ("__str__", &ToString>) .def(py::self==py::self) .def(py::self+py::self) @@ -230,6 +242,8 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m) .def("__len__", [](Vec<3>& /*unused*/) { return 3; }) ; + py::implicitly_convertible>(); + m.def ("Vec", FunctionPointer ([] (double x, double y, double z) { return global_trafo(Vec<3>(x,y,z)); })); m.def("Vec", [](py::array_t np_array) From 7a1344bfcb54cf32cf66a006d5ddf0ddfa1ea9ef Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Thu, 1 Oct 2020 13:35:53 +0200 Subject: [PATCH 181/384] cmake variable NG_COMPILE_FLAGS to set additional compile options --- CMakeLists.txt | 2 ++ cmake/SuperBuild.cmake | 1 + libsrc/core/CMakeLists.txt | 2 ++ 3 files changed, 5 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index c756c441..7916e6ee 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,6 +34,8 @@ option( BUILD_FOR_CONDA "Link python libraries only to executables" OFF) option( USE_SUPERBUILD "use ccache" ON) +set(NG_COMPILE_FLAGS "" CACHE STRING "Additional compile flags") + set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH}" "${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake_modules") if(APPLE) diff --git a/cmake/SuperBuild.cmake b/cmake/SuperBuild.cmake index e28c034b..37709768 100644 --- a/cmake/SuperBuild.cmake +++ b/cmake/SuperBuild.cmake @@ -145,6 +145,7 @@ set_vars( NETGEN_CMAKE_ARGS CHECK_RANGE BUILD_STUB_FILES BUILD_FOR_CONDA + NG_COMPILE_FLAGS ) # propagate all variables set on the command line using cmake -DFOO=BAR diff --git a/libsrc/core/CMakeLists.txt b/libsrc/core/CMakeLists.txt index a2873ed9..8329a195 100644 --- a/libsrc/core/CMakeLists.txt +++ b/libsrc/core/CMakeLists.txt @@ -14,6 +14,8 @@ add_library(ngcore SHARED version.cpp ) +target_compile_options(ngcore PUBLIC "${NG_COMPILE_FLAGS}") + # Pybind11 2.3 Issue https://github.com/pybind/pybind11/issues/1604 if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") target_compile_options(ngcore PUBLIC -fsized-deallocation -faligned-allocation) From 2629208f380af72be6e9cd1167f6c4e88375fdae Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Thu, 8 Oct 2020 12:20:46 +0200 Subject: [PATCH 182/384] pajetrace - fix Timer names in MPI-trace --- libsrc/core/paje_trace.cpp | 40 ++++++++++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/libsrc/core/paje_trace.cpp b/libsrc/core/paje_trace.cpp index 4787d213..3b285830 100644 --- a/libsrc/core/paje_trace.cpp +++ b/libsrc/core/paje_trace.cpp @@ -16,6 +16,19 @@ constexpr int MPI_PAJE_WRITER = 1; namespace ngcore { + static std::string GetTimerName( int id ) + { +#ifndef PARALLEL + return NgProfiler::GetName(id); +#else // PARALLEL + if(id1) @@ -718,13 +745,10 @@ namespace ngcore std::map timer_names; for(auto & event : timer_events) - { - event.timer_id += NgProfiler::SIZE*rank; timer_ids.insert(event.timer_id); - } for(auto id : timer_ids) - timer_names[id] = NgProfiler::GetName(id-NgProfiler::SIZE*rank); + timer_names[id] = GetTimerName(id); size_t size = timer_ids.size(); comm.Send(size, MPI_PAJE_WRITER, 0); for(auto id : timer_ids) @@ -844,7 +868,7 @@ namespace ngcore if(need_init) { - current->name = is_timer_event ? NgProfiler::GetName(id) : job_names[id]; + current->name = is_timer_event ? GetTimerName(id) : job_names[id]; current->time = 0.0; current->id = id; } From b5a9580a8e0a23d0508b6bd5da1463937eb716fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20Sch=C3=B6berl?= Date: Thu, 8 Oct 2020 21:27:16 +0200 Subject: [PATCH 183/384] BitArray::Data --- libsrc/core/bitarray.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libsrc/core/bitarray.hpp b/libsrc/core/bitarray.hpp index 4005fc81..768b40df 100644 --- a/libsrc/core/bitarray.hpp +++ b/libsrc/core/bitarray.hpp @@ -148,7 +148,8 @@ public: NGCORE_API size_t NumSet () const; NGCORE_API void DoArchive(Archive& archive); - + + NGCORE_API auto * Data() const { return data; } private: /// unsigned char Mask (size_t i) const From b81f7f5adaf8ef95189f9f28520ef68839d73b99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20Sch=C3=B6berl?= Date: Sun, 11 Oct 2020 13:26:34 +0200 Subject: [PATCH 184/384] improve robustness for revolution surface meshing (FindSpecialPoints) --- libsrc/csg/revolution.cpp | 22 +++++++- libsrc/csg/revolution.hpp | 5 +- libsrc/csg/specpoin.cpp | 102 +++++++++++++++++++++++++++++++++++--- libsrc/csg/specpoin.hpp | 3 ++ 4 files changed, 123 insertions(+), 9 deletions(-) diff --git a/libsrc/csg/revolution.cpp b/libsrc/csg/revolution.cpp index 57498cb4..28e96a4f 100644 --- a/libsrc/csg/revolution.cpp +++ b/libsrc/csg/revolution.cpp @@ -670,6 +670,23 @@ namespace netgen surfaceactive.Append(1); surfaceids.Append(0); } + + // checking + if (type == 2) + { + auto t0 = spline_in.GetSpline(0).GetTangent(0); + cout << "tstart (must be vertically): " << t0 << endl; + + auto tn = spline_in.GetSpline(nsplines-1).GetTangent(1); + cout << "tend (must be vertically): " << tn << endl; + + for (int i = 0; i < nsplines-1; i++) + { + auto ta = spline_in.GetSpline(i).GetTangent(1); + auto tb = spline_in.GetSpline(i+1).GetTangent(0); + cout << "sin (must not be 0) = " << abs(ta(0)*tb(1)-ta(1)*tb(0)) / (Abs(ta)*Abs(tb)); + } + } } Revolution::~Revolution() @@ -764,8 +781,9 @@ namespace netgen int intersections_before(0), intersections_after(0); double randomx = 7.42357; double randomy = 1.814756; - randomx *= 1./sqrt(randomx*randomx+randomy*randomy); - randomy *= 1./sqrt(randomx*randomx+randomy*randomy); + double randomlen = sqrt(randomx*randomx+randomy*randomy); + randomx *= 1./randomlen; + randomy *= 1./randomlen; const double a = randomy; diff --git a/libsrc/csg/revolution.hpp b/libsrc/csg/revolution.hpp index 0a395e3f..8f3d72d5 100644 --- a/libsrc/csg/revolution.hpp +++ b/libsrc/csg/revolution.hpp @@ -67,7 +67,10 @@ namespace netgen virtual double MaxCurvature () const; //virtual double MaxCurvatureLoc (const Point<3> & /* c */ , // double /* rad */) const; - + + Point<3> P0() const { return p0; } + Vec<3> Axis() const { return v_axis; } + virtual void Project (Point<3> & p) const; virtual Point<3> GetSurfacePoint () const; diff --git a/libsrc/csg/specpoin.cpp b/libsrc/csg/specpoin.cpp index 1855508c..c3231140 100644 --- a/libsrc/csg/specpoin.cpp +++ b/libsrc/csg/specpoin.cpp @@ -463,8 +463,35 @@ namespace netgen return; } - } + if (numprim == 2 && + (typeid(*geometry->GetSurface(locsurf[0])) == typeid(RevolutionFace&)) && + (typeid(*geometry->GetSurface(locsurf[1])) == typeid(RevolutionFace&))) + { + NgArray> pts; + bool check = + ComputeExtremalPoints (static_cast (geometry->GetSurface(locsurf[0])), + static_cast (geometry->GetSurface(locsurf[1])), + pts); + if (check) + { + // int cnt_inbox = 0; + for (auto p : pts) + if (box.IsIn(p)) + { + AddPoint (p, layer); + // cnt_inbox++; + } + return; + /* + if (cnt_inbox == 0) + return; + */ + } + } + + } // end if (numprim <= check_crosspoint) + possiblecrossp = (numprim >= 3) && calccp; @@ -608,9 +635,9 @@ namespace netgen decision = 0; } } - - // (*testout) << "l = " << level << " dec/sureexp = " << decision << sureexp << endl; - +#ifdef DEVELOP + (*testout) << "edgepnt decision = " << decision << " sure = " << sureexp << endl; +#endif if (decision && sureexp) { for (int k1 = 0; k1 < locsurf.Size() - 1; k1++) @@ -890,9 +917,18 @@ namespace netgen f1->CalcGradient (p, g1); f2->CalcGradient (p, g2); - if ( sqr (g1 * g2) > (1 - 1e-10) * Abs2 (g1) * Abs2 (g2)) - return 1; + // if ( sqr (g1 * g2) > (1 - 1e-10) * Abs2 (g1) * Abs2 (g2)) + // return 1; + if ( Abs2 (Cross(g1,g2)) < 1e-10 * Abs2 (g1) * Abs2 (g2)) // same, but stable + { + if (Abs2(vrs) < 1e-12*sqr(size)) // degenerate only if on both surfaces + return 1; + else + return 0; + } + + for (int j = 0; j < 3; j++) { mat(0,j) = g1(j); @@ -1534,7 +1570,61 @@ namespace netgen } + bool SpecialPointCalculation :: + ComputeExtremalPoints (const RevolutionFace * rev1, + const RevolutionFace * rev2, + NgArray > & pts) + { + // if (rev1 -> P0() != rev2 -> P0()) return false; // missing ???? + if (Dist2 (rev1 -> P0(), rev2 -> P0()) > 1e-20*sqr(size)) return false; + // if (rev1 -> Axis() != rev2 -> Axis()) return false; + if ( (rev1 -> Axis()-rev2 -> Axis()).Length2() > 1e-16) return false; + Point<2> p1s = rev1->GetSpline().StartPI(); + Point<2> p1e = rev1->GetSpline().EndPI(); + Point<2> p2s = rev2->GetSpline().StartPI(); + Point<2> p2e = rev2->GetSpline().EndPI(); + + Point<2> p2d; + if (Dist2(p1s,p2e) < 1e-20*sqr(size)) + p2d = p1s; + else if (Dist2(p1e, p2s) < 1e-20*sqr(size)) + p2d = p1e; + else + return false; + *testout << "Norm axis = " << rev1->Axis().Length() << endl; + Point<3> center = rev1->P0() + p2d(0)*rev1->Axis(); + Vec<3> n = rev1->Axis(); + // extremal points of circle, center, normal axis, radius p2d(1) + // Lagrange: + // L(x, lam1, lam2) = x_i + lam1 * (x-c)*v + lam2 * ( |x-c|^2 - r^2 ) + for (double i = 0; i < 3; i++) + { + double lam1 = -n(i) / n.Length2(); + Vec<3> ei(0,0,0); ei(i) = 1; + // double lam2 = 1/(2*p2d(1)) * sqrt(1 - sqr(n(i))/n.Length2()); + double fac = 1-sqr(n(i))/n.Length2(); + // if (fabs(lam2) > 1e-10) + if (fac > 1e-10) + { + double lam2 = 1/(2*p2d(1)) * sqrt(fac); + Point<3> x = center - 1.0/(2*lam2) * (ei + lam1*n); + pts.Append (x); + x = center + 1.0/(2*lam2) * (ei + lam1*n); + pts.Append (x); + + /* + // check: + Point<2> p2d; + rev1 -> CalcProj (x, p2d); + *testout << "special solution, p2d = " << p2d << endl; + rev2 -> CalcProj (x, p2d); + *testout << "special solution, p2d = " << p2d << endl; + */ + } + } + return true; + } diff --git a/libsrc/csg/specpoin.hpp b/libsrc/csg/specpoin.hpp index a4210a15..40e70a82 100644 --- a/libsrc/csg/specpoin.hpp +++ b/libsrc/csg/specpoin.hpp @@ -167,6 +167,9 @@ namespace netgen const Sphere * sphere2, NgArray > & pts); + bool ComputeExtremalPoints (const RevolutionFace * rev1, + const RevolutionFace * rev2, + NgArray > & pts); void ComputeCrossPoints (const Plane * plane1, const Plane * plane2, From a894ebc9f5dd599f1290b85554f9883a07965e0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20Sch=C3=B6berl?= Date: Sun, 11 Oct 2020 22:16:47 +0200 Subject: [PATCH 185/384] stable pseudo-inverse, improve edge-analysis for revolution --- libsrc/csg/revolution.cpp | 61 ++++++++++++++++++++++++++++++++++++++ libsrc/csg/revolution.hpp | 5 +++- libsrc/csg/specpoin.cpp | 25 ++++++++++++---- libsrc/csg/surface.hpp | 4 +++ libsrc/gprim/geomfuncs.hpp | 39 ++++++++++++++++++++++++ 5 files changed, 127 insertions(+), 7 deletions(-) diff --git a/libsrc/csg/revolution.cpp b/libsrc/csg/revolution.cpp index 28e96a4f..36f7c614 100644 --- a/libsrc/csg/revolution.cpp +++ b/libsrc/csg/revolution.cpp @@ -948,6 +948,67 @@ namespace netgen return VecInSolid(p,v1+0.01*v2,eps); } + + void Revolution :: + GetTangentialVecSurfaceIndices2 (const Point<3> & p, const Vec<3> & v1, const Vec<3> & v2, + NgArray & surfind, double eps) const + { + *testout << "tangentialvecsurfind2, p = " << p << endl; + for (int i = 0; i < faces.Size(); i++) + if (faces[i]->PointInFace (p, eps)) + { + *testout << "check face " << i << endl; + Point<2> p2d; + Vec<2> v12d; + faces[i]->CalcProj(p,p2d,v1,v12d); + *testout << "v12d = " << v12d << endl; + auto & spline = faces[i]->GetSpline(); + if (Dist2 (spline.StartPI(), p2d) < sqr(eps)) + { + *testout << "start pi" << endl; + Vec<2> tang = spline.GetTangent(0); + double ip = tang*v12d; + *testout << "ip = " << ip << endl; + if (ip > eps) + surfind.Append(GetSurfaceId(i)); + else if (ip > -eps) + { + Vec<2> v22d; + faces[i]->CalcProj(p,p2d,v2,v22d); + double ip2 = tang*v22d; + *testout << "ip2 = " << ip2 << endl; + if (ip2 > -eps) + surfind.Append(GetSurfaceId(i)); + } + } + else if (Dist2 (faces[i]->GetSpline().EndPI(), p2d) < sqr(eps)) + { + *testout << "end pi" << endl; + + Vec<2> tang = spline.GetTangent(1); + double ip = tang*v12d; + *testout << "ip = " << ip << endl; + if (ip < -eps) + surfind.Append(GetSurfaceId(i)); + else if (ip < eps) + { + Vec<2> v22d; + faces[i]->CalcProj(p,p2d,v2,v22d); + double ip2 = tang*v22d; + *testout << "ip2 = " << ip2 << endl; + if (ip2 < eps) + surfind.Append(GetSurfaceId(i)); + } + } + else + { + *testout << "inner point" << endl; + surfind.Append(GetSurfaceId(i)); + } + } + } + + int Revolution :: GetNSurfaces() const { diff --git a/libsrc/csg/revolution.hpp b/libsrc/csg/revolution.hpp index 8f3d72d5..67f9d9c9 100644 --- a/libsrc/csg/revolution.hpp +++ b/libsrc/csg/revolution.hpp @@ -158,7 +158,10 @@ namespace netgen const Vec<3> & v2, double eps) const; - + virtual void GetTangentialVecSurfaceIndices2 (const Point<3> & p, const Vec<3> & v1, const Vec<3> & v2, + NgArray & surfind, double eps) const; + + virtual int GetNSurfaces() const; virtual Surface & GetSurface (int i = 0); virtual const Surface & GetSurface (int i = 0) const; diff --git a/libsrc/csg/specpoin.cpp b/libsrc/csg/specpoin.cpp index c3231140..16024e95 100644 --- a/libsrc/csg/specpoin.cpp +++ b/libsrc/csg/specpoin.cpp @@ -1908,8 +1908,11 @@ namespace netgen } - if (Abs2 (t) < 1e-8) - continue; + if (Abs2 (t) < 1e-16) + { + cerr << "normal vectors degenerated" << endl; + continue; + } #ifdef DEVELOP *testout << " tangential vector " << t << endl; @@ -1950,10 +1953,15 @@ namespace netgen rhs(0) = -t * (hessej * t); rhs(1) = -t * (hessek * t); - CalcInverse (mat, inv); - t2 = inv * rhs; + CalcInverse (mat, inv); + t2 = inv * rhs; + // t2 = StableSolve (mat, rhs); +#ifdef DEVELOP + *testout << "t = " << t << ", t2 = " << t2 << endl; +#endif - + + /* ageometry.GetIndependentSurfaceIndices (locsol, p, t, surfind2); @@ -2010,7 +2018,9 @@ namespace netgen // locsol2 -> TangentialSolid2 (p, m1, locsol3, surfind3, 1e-9*geomsize); locsol -> TangentialEdgeSolid (p, t, t2, m1, locsol3, surfind3, ideps*geomsize); - +#ifdef DEVELOP + (*testout) << "m1 = " << m1 << ", surfind3 = " << surfind3 << endl; +#endif //ageometry.GetIndependentSurfaceIndices (surfind3); if (surfind3.Contains(surfind2[l])) @@ -2019,6 +2029,9 @@ namespace netgen // locsol2 -> TangentialSolid2 (p, m2, locsol3, surfind3, 1e-9*geomsize); locsol -> TangentialEdgeSolid (p, t, t2, m2, locsol3, surfind3, ideps*geomsize); +#ifdef DEVELOP + (*testout) << "m2 = " << m2 << ", surfind3 = " << surfind3 << endl; +#endif // ageometry.GetIndependentSurfaceIndices (surfind3); diff --git a/libsrc/csg/surface.hpp b/libsrc/csg/surface.hpp index a17fd3da..d2b52cbe 100644 --- a/libsrc/csg/surface.hpp +++ b/libsrc/csg/surface.hpp @@ -293,9 +293,13 @@ namespace netgen const Vec<3> & m, double eps) const; + // for a point p in the surface, into which (closed) surfaces does v point into ? virtual void GetTangentialVecSurfaceIndices (const Point<3> & p, const Vec<3> & v, NgArray & surfind, double eps) const; + // a point p in the surface, and v a tangential vector + // for arbitrary small, but positive t consider q := Project(p+t*v) + // into which (closed) surfaces does v2 point into, when starting from q ? virtual void GetTangentialVecSurfaceIndices2 (const Point<3> & p, const Vec<3> & v1, const Vec<3> & v2, NgArray & surfind, double eps) const; diff --git a/libsrc/gprim/geomfuncs.hpp b/libsrc/gprim/geomfuncs.hpp index ea0070df..c85e0dc6 100644 --- a/libsrc/gprim/geomfuncs.hpp +++ b/libsrc/gprim/geomfuncs.hpp @@ -142,10 +142,24 @@ namespace netgen inline void CalcInverse (const Mat<2,3> & m, Mat<3,2> & inv) { + Vec<3> a0 = m.Row(0); + Vec<3> a1 = m.Row(1); + Vec<3> n = Cross(a0, a1); + Vec<3> d0 = Cross(a1, n); + Vec<3> d1 = Cross(a0, n); + double s0 = 1.0/(a0*d0); + double s1 = 1.0/(a1*d1); + for (int i = 0; i < 3; i++) + { + inv(i,0) = s0*d0(i); + inv(i,1) = s1*d1(i); + } + /* Mat<2,2> a = m * Trans (m); Mat<2,2> ainv; CalcInverse (a, ainv); inv = Trans (m) * ainv; + */ } void CalcInverse (const Mat<3,2> & m, Mat<2,3> & inv); @@ -166,6 +180,31 @@ namespace netgen void EigenValues (const Mat<3,3> & m, Vec<3> & ev); void EigenValues (const Mat<2,2> & m, Vec<3> & ev); + + template + Vec<3,T> StableSolve (Mat<2,3,T> mat, Vec<2,T> rhs) + { + Vec<3> a0 = mat.Row(0); + Vec<3> a1 = mat.Row(1); + /* + Vec<3> d = Cross ( Cross (a0, a1), a0); + + double alpha = rhs(0) / a0.Length2(); + double beta = (rhs(1)-alpha* (a0*a1)) / (d*a1); + return alpha * a0 + beta * d; + */ + Vec<3> n = Cross(a0, a1); + Vec<3> d0 = Cross(a1, n); + Vec<3> d1 = Cross(a0, n); + double alpha = rhs(0) / (a0*d0); + double beta = rhs(1) / (a1*d1); + return alpha * d0 + beta * d1; + } + + + + + } #endif From 25efdadd057aa0d5261dc93608a61943d425cc48 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Tue, 13 Oct 2020 11:11:33 +0200 Subject: [PATCH 186/384] helper macro for Timer/RegionTimer definition --- libsrc/core/profiler.hpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/libsrc/core/profiler.hpp b/libsrc/core/profiler.hpp index 36c10d55..c16c242c 100644 --- a/libsrc/core/profiler.hpp +++ b/libsrc/core/profiler.hpp @@ -301,5 +301,14 @@ namespace ngcore } // namespace ngcore +// Helper macro to easily add multiple timers in a function for profiling +// Usage: NETGEN_TIMER_FROM_HERE("my_timer_name") +// Effect: define static Timer and RegionTimer with given name and line number +#define NETGEN_TOKEN_CONCAT(x, y) x ## y +#define NETGEN_TOKEN_CONCAT2(x, y) NETGEN_TOKEN_CONCAT(x, y) +#define NETGEN_TIMER_FROM_HERE(name) \ + static Timer NETGEN_TOKEN_CONCAT2(timer_, __LINE__)( string(name)+"_"+ToString(__LINE__)); \ + RegionTimer NETGEN_TOKEN_CONCAT2(rt_,__LINE__)(NETGEN_TOKEN_CONCAT2(timer_,__LINE__)); + #endif // NETGEN_CORE_PROFILER_HPP From 14e6a1d24b9aa01ad7756dd2089db7c5a680b416 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Tue, 13 Oct 2020 12:04:13 +0200 Subject: [PATCH 187/384] more statistics in sunburst chart --- libsrc/core/paje_trace.cpp | 42 ++++++++++++++++++++++++++++++++++---- 1 file changed, 38 insertions(+), 4 deletions(-) diff --git a/libsrc/core/paje_trace.cpp b/libsrc/core/paje_trace.cpp index 3b285830..6840b16c 100644 --- a/libsrc/core/paje_trace.cpp +++ b/libsrc/core/paje_trace.cpp @@ -785,7 +785,11 @@ namespace ngcore { int id = 0; std::map 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; std::string name; TTimePoint start_time = 0; }; @@ -793,7 +797,13 @@ namespace ngcore void PrintNode (const TreeNode &n, int &level, std::ofstream & f); void PrintNode (const TreeNode &n, int &level, std::ofstream & f) { - f << "{ name: \"" + n.name + "\", size: " + ToString(n.time); + 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; int size = n.children.size(); if(size>0) { @@ -815,7 +825,6 @@ namespace ngcore std::vector events; TreeNode root; - root.time=0; root.name="all"; TreeNode *current = &root; @@ -853,6 +862,9 @@ namespace ngcore std::sort (events.begin(), events.end()); root.time = 1000.0*static_cast(stop_time) * seconds_per_tick; + root.calls = 1; + root.min_time = root.time; + root.max_time = root.time; for(auto & event : events) { @@ -883,12 +895,19 @@ namespace ngcore } double time = 1000.0*static_cast(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); + current->calls++; + current = node_stack.back(); - current->time -= time; + current->chart_size -= time; node_stack.pop_back(); } } + root.chart_size = 0.0; + int level = 0; std::ofstream f(tracefile_name+".html"); f.precision(4); @@ -910,11 +929,26 @@ namespace ngcore 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)) - .tooltipContent((d, node) => `Time: ${node.value.toPrecision(6)}ms`) + .tooltipContent((d, node) => { + return `Time: ${getTime(d.time)}
` + + `calls: ${d.calls}
` + + `min: ${getTime(d.min)}
` + + `max: ${getTime(d.max)}
` + + `avg: ${getTime(d.avg)}` + }) (document.getElementById('chart')); From 6544fbeca6835354991a667b43524cd182e405b1 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Wed, 14 Oct 2020 11:39:56 +0200 Subject: [PATCH 188/384] sunburst chart - tooltip formatting --- libsrc/core/paje_trace.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/libsrc/core/paje_trace.cpp b/libsrc/core/paje_trace.cpp index 6840b16c..c58912a4 100644 --- a/libsrc/core/paje_trace.cpp +++ b/libsrc/core/paje_trace.cpp @@ -942,6 +942,7 @@ namespace ngcore .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: ${getTime(d.time)}
` + `calls: ${d.calls}
` @@ -950,6 +951,12 @@ namespace ngcore + `avg: ${getTime(d.avg)}` }) (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 = ""; + } )CODE_" << std::endl; From 33bb84bd3e705e914f8e99f712cf571c3a5f236d Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Wed, 14 Oct 2020 11:54:36 +0200 Subject: [PATCH 189/384] CSG2d optimizations (in-place operators, search tree) --- libsrc/geom2d/csg2d.cpp | 256 +++++++++++++++++++++++++++++++++++----- libsrc/geom2d/csg2d.hpp | 62 +++++++++- 2 files changed, 282 insertions(+), 36 deletions(-) diff --git a/libsrc/geom2d/csg2d.cpp b/libsrc/geom2d/csg2d.cpp index e945c586..20e021c6 100644 --- a/libsrc/geom2d/csg2d.cpp +++ b/libsrc/geom2d/csg2d.cpp @@ -673,6 +673,7 @@ void AddIntersectionPoint(Edge edgeP, Edge edgeQ, IntersectionType i, double alp void ComputeIntersections(Solid2d & sp, Solid2d & sq) { + static Timer tall("ComputeIntersections"); RegionTimer rtall(tall); auto & PP = sp.polys; auto & QQ = sq.polys; @@ -1246,6 +1247,7 @@ void CleanUpResult(Solid2d & sr) void RemoveDuplicates(Solid2d & sr) { + static Timer tall("RemoveDuplicates"); RegionTimer rtall(tall); for(auto & poly : sr.polys) { if(poly.first==nullptr) continue; @@ -1308,12 +1310,142 @@ void AddIntersectionPoints ( Solid2d & s1, Solid2d & s2 ) RemoveDuplicates(s2); } -Solid2d ClipSolids ( Solid2d s1, Solid2d s2, bool intersect) +Solid2d ClipSolids ( const Solid2d & s1, const Solid2d & s2, char op) { + return ClipSolids(Solid2d{s1}, Solid2d{s2}, op); +} + +Solid2d ClipSolids ( const Solid2d & s1, Solid2d && s2, char op) +{ + return ClipSolids(Solid2d{s1}, std::move(s2), op); +} + +Solid2d ClipSolids ( Solid2d && s1, const Solid2d & s2, char op) +{ + return ClipSolids(std::move(s1), Solid2d{s2}, op); +} + +Solid2d ClipSolids ( Solid2d && s1, Solid2d && s2, char op) +{ + static Timer tall("ClipSolids"); RegionTimer rtall(tall); + static Timer t0("copy"); + static Timer t02("tree"); + static Timer t03("search intersections"); + static Timer t01("prepare"); static Timer t1("intersection"); static Timer t2("label"); static Timer t3("cut"); static Timer t4("cleanup"); + static Timer t6("trivial union"); + + bool intersect = (op=='*' || op=='-'); + + Solid2d res; + res.name = s1.name; + + t0.Start(); + // Try to quickly handle parts of both solids that cannot intersect with the other one + int n1 = s1.polys.Size(); + int n2 = s2.polys.Size(); + Array res_polys(n1+n2); + res_polys.SetSize(0); + + t02.Start(); + netgen::Box<2> s1_box(netgen::Box<2>::EMPTY_BOX); + netgen::BoxTree <2, int> tree1(s1.GetBoundingBox()); + + for(auto li : IntRange(n1)) + { + auto box = s1.polys[li].GetBoundingBox(); + s1_box.Add(box.PMin()); + s1_box.Add(box.PMax()); + tree1.Insert(box, li); + } + + netgen::Box<2> s2_box(netgen::Box<2>::EMPTY_BOX); + netgen::BoxTree <2, int> tree2(s2.GetBoundingBox()); + + for(auto li : IntRange(n2)) + { + auto box = s2.polys[li].GetBoundingBox(); + s2_box.Add(box.PMin()); + s2_box.Add(box.PMax()); + tree2.Insert(box, li); + } + t02.Stop(); + + t03.Start(); + + for(auto li : IntRange(n1)) + { + bool have_intersections = false; + auto & poly = s1.polys[li]; + auto box = poly.GetBoundingBox(); + tree2.GetFirstIntersecting(box.PMin(), box.PMax(), [&] (int li2) + { + return have_intersections = true; + }); + if(!have_intersections) + { + if(op=='+' || op=='-') + res_polys.Append(std::move(poly)); + else + poly.Clear(); + } + } + t03.Stop(); + + for(auto li: IntRange(n1)) + while(s1.polys.Size()>li && s1.polys[li].Size()==0) + s1.polys.DeleteElement(li); + + t03.Start(); + for(auto li : IntRange(n2)) + { + bool have_intersections = false; + auto & poly = s2.polys[li]; + auto box = poly.GetBoundingBox(); + tree1.GetFirstIntersecting(box.PMin(), box.PMax(), [&] (int li2) + { + return have_intersections = true; + }); + if(!have_intersections) + { + if(op=='+') + res_polys.Append(std::move(poly)); + else + poly.Clear(); + } + } + t03.Stop(); + + for(auto li: IntRange(n2)) + while(s2.polys.Size()>li && s2.polys[li].Size()==0) + s2.polys.DeleteElement(li); + + t0.Stop(); + + if(s1.polys.Size()==0 || s2.polys.Size()==0) + { + res.polys = std::move(res_polys); + return res; + } + RegionTracer rt_(0, tall, s1.polys.Size()*10000 + s2.polys.Size()); + + t01.Start(); + + if(op=='-') + { + // take complement of s2 by adding loop around everything + auto box = s1_box; + box.Add(s2_box.PMin()); + box.Add(s2_box.PMax()); + box.Increase(2); + auto pmin = box.PMin(); + auto pmax = box.PMax(); + s2.Append(RectanglePoly(pmin[0], pmax[0], pmin[1], pmax[1], "JUST_FOR_CLIPPING")); + } + for(auto & poly : s1.polys) for(auto v : poly.Vertices(ALL)) @@ -1337,8 +1469,7 @@ Solid2d ClipSolids ( Solid2d s1, Solid2d s2, bool intersect) v->enex = NEITHER; } - Solid2d res; - res.name = s1.name; + t01.Stop(); t1.Start(); ComputeIntersections(s1, s2); @@ -1357,7 +1488,9 @@ Solid2d ClipSolids ( Solid2d s1, Solid2d s2, bool intersect) RemoveDuplicates(res); t4.Stop(); - return res; + res.polys.Append(std::move(res_polys)); + + return std::move(res); } bool Loop :: IsInside( Point<2> r ) const @@ -1396,6 +1529,16 @@ bool Loop :: IsInside( Point<2> r ) const return ( (w % 2) != 0 ); } +netgen::Box<2> Loop :: GetBoundingBox() const +{ + // static Timer tall("Loop::GetBoundingBox"); RegionTimer rtall(tall); + netgen::Box<2> box(netgen::Box<2>::EMPTY_BOX); + for(auto v : Vertices(ALL)) + box.Add(*v); + return box; +} + + Solid2d :: Solid2d(const Array, EdgeInfo>> & points, string name_, string bc) : name(name_) { @@ -1422,47 +1565,38 @@ Solid2d :: Solid2d(const Array, EdgeInfo>> & points, strin Solid2d Solid2d :: operator+(const Solid2d & other) const { - if(polys.Size()==0) - return other; - - auto res = ClipSolids(*this, other, false); - res.name = name; - return res; + static Timer t("Solid2d::operator+"); RegionTimer rt(t); + return ClipSolids(*this, other, '+'); } Solid2d Solid2d :: operator*(const Solid2d & other) const { - auto res = ClipSolids(*this, other, true); - res.name = name; - return res; + static Timer t("Solid2d::operator*"); RegionTimer rt(t); + return ClipSolids(*this, other, '*'); } -Solid2d Solid2d :: operator-(const Solid2d & other_) const +Solid2d Solid2d :: operator-(const Solid2d & other) const { - // TODO: Check dimensions of solids with bounding box - Solid2d other = other_; - other.Append(RectanglePoly(-1e8, 1e8, -1e8, 1e8, "JUST_FOR_CLIPPING")); - auto res = ClipSolids(*this, other); - - res.name = name; - return res; + static Timer t("Solid2d::operator-"); RegionTimer rt(t); + return ClipSolids(*this, other, '-'); } Solid2d & Solid2d :: operator+=(const Solid2d & other) { - *this = *this + other; + static Timer t("Solid2d::operator+="); RegionTimer rt(t); + *this = ClipSolids(std::move(*this), other, '+'); return *this; } Solid2d & Solid2d :: operator*=(const Solid2d & other) { - *this = *this * other; + *this = ClipSolids(std::move(*this), other, '*'); return *this; } Solid2d & Solid2d :: operator-=(const Solid2d & other) { - *this = *this - other; + *this = ClipSolids(std::move(*this), other, '-'); return *this; } @@ -1504,6 +1638,42 @@ bool Solid2d :: IsInside( Point<2> r ) const return ( (w % 2) != 0 ); } +bool Loop :: IsLeftInside( const Vertex & p0 ) +{ + auto & p1 = *p0.next; + if(p0.spline) + { + auto s = *p0.spline; + auto v = s.GetTangent(0.5); + auto n = Vec<2>{-v[1], v[0]}; + auto q = s.GetPoint(0.5) + 1e-6*n; + return IsInside(q); + } + auto v = p1-p0; + auto n = Vec<2>{-v[1], v[0]}; + auto q = p0 + 0.5*v + 1e-6*n; + + return IsInside(q); +} + +bool Loop :: IsRightInside( const Vertex & p0 ) +{ + auto & p1 = *p0.next; + if(p0.spline) + { + auto s = *p0.spline; + auto v = s.GetTangent(0.5); + auto n = Vec<2>{v[1], -v[0]}; + auto q = s.GetPoint(0.5) + 1e-6*n; + return IsInside(q); + } + + auto v = p1-p0; + auto n = Vec<2>{v[1], -v[0]}; + auto q = p0 + 0.5*v + 1e-6*n; + return IsInside(q); +} + bool Solid2d :: IsLeftInside( const Vertex & p0 ) { auto & p1 = *p0.next; @@ -1540,20 +1710,27 @@ bool Solid2d :: IsRightInside( const Vertex & p0 ) return IsInside(q); } -netgen::Box<2> Solid2d :: GetBoundingBox() +netgen::Box<2> Solid2d :: GetBoundingBox() const { + static Timer tall("Solid2d::GetBoundingBox"); RegionTimer rtall(tall); netgen::Box<2> box(netgen::Box<2>::EMPTY_BOX); for(auto & poly : polys) - for(auto v : poly.Vertices(ALL)) - box.Add(*v); + { + auto pbox = poly.GetBoundingBox(); + box.Add(pbox.PMin()); + box.Add(pbox.PMax()); + } return box; } shared_ptr CSG2d :: GenerateSplineGeometry() { - static Timer t_intersections("CSG2d - AddIntersections()"); static Timer tall("CSG2d - GenerateSplineGeometry()"); + static Timer t_points("add points"); + static Timer t_segments_map("build segments map"); + static Timer t_segments("add segments"); + static Timer t_intersections("add intersections"); RegionTimer rt(tall); struct Seg @@ -1618,6 +1795,7 @@ shared_ptr CSG2d :: GenerateSplineGeometry() return res; }; + t_points.Start(); auto insertPoint = [&](Point<2> p ) { int pi = getPoint(p); @@ -1640,9 +1818,11 @@ shared_ptr CSG2d :: GenerateSplineGeometry() if(v->spline) insertPoint(v->spline->TangentPoint()); } + t_points.Stop(); // Generate segments from polygon edges and find left/right domain of each segment + t_segments_map.Start(); int dom = 0; int bc = 1; for(auto & s : solids) @@ -1651,6 +1831,10 @@ shared_ptr CSG2d :: GenerateSplineGeometry() bool is_solid_degenerated = true; // Don't create new domain for degenerated solids for(auto & poly : s.polys) { + bool first = true; + bool is_poly_left_inside = false; + bool is_poly_right_inside = false; + for(auto v : poly.Vertices(ALL)) { auto & p0 = *v; @@ -1675,8 +1859,15 @@ shared_ptr CSG2d :: GenerateSplineGeometry() Swap(pi1,pi0); } - auto li = s.IsLeftInside(p0); - auto ri = s.IsRightInside(p0); + if(first) + { + is_poly_left_inside = s.IsLeftInside(p0); + is_poly_right_inside = s.IsRightInside(p0); + first = true; + } + + auto li = is_poly_left_inside; // == poly.IsLeftInside(p0); + auto ri = is_poly_right_inside; // == poly.IsRightInside(p0); auto & ls = seg_map[{pi0,pi1,pi2}]; ls.p0 = pi0; @@ -1694,7 +1885,7 @@ shared_ptr CSG2d :: GenerateSplineGeometry() if(li!=ri) { - if(s.IsLeftInside(p0) != flip) + if(li != flip) ls.left = dom; else ls.right = dom; @@ -1708,10 +1899,12 @@ shared_ptr CSG2d :: GenerateSplineGeometry() else dom--; // degenerated solid, use same domain index again } + t_segments_map.Stop(); for(auto bc : Range(bcnames)) geo->SetBCName(bc+1, bcnames[bc]); + t_segments.Start(); for(auto const &m : seg_map) { auto ls = m.second; @@ -1737,6 +1930,7 @@ shared_ptr CSG2d :: GenerateSplineGeometry() seg->hmax = ls.maxh; geo->AppendSegment(seg); } + t_segments.Stop(); return geo; } diff --git a/libsrc/geom2d/csg2d.hpp b/libsrc/geom2d/csg2d.hpp index eeb1a75b..938032ba 100644 --- a/libsrc/geom2d/csg2d.hpp +++ b/libsrc/geom2d/csg2d.hpp @@ -95,6 +95,12 @@ struct EdgeInfo struct Vertex : Point<2> { Vertex (Point<2> p) : Point<2>(p) {} + Vertex (const Vertex & v) : Point<2>(v) + { + spline = v.spline; + info = v.info; + is_source = true; + } Vertex * prev = nullptr; Vertex * next = nullptr; @@ -399,15 +405,49 @@ struct Loop AppendVertex(*v); } + Loop(Loop && p) = default; + + Loop & operator=(Loop && p) = default; + Loop & operator=(const Loop & p) { + // static Timer t("Loop::operator="); RegionTimer rt(t); first = nullptr; if(p.first) - for(const auto v : p.Vertices(ALL)) - AppendVertex(*v); + { + size_t n = p.Size(); + Array> new_verts(n); + { + size_t i = 0; + for(const auto v : p.Vertices(ALL)) + new_verts[i++] = make_unique(*v); + } + + for(auto i : IntRange(n-1)) + { + Vertex * v = new_verts[i].get(); + Vertex * vn = new_verts[i+1].get(); + v->next = vn; + vn->prev = v; + } + Vertex * vfirst = new_verts[0].get(); + Vertex * vlast = new_verts[n-1].get(); + vfirst->prev = vlast; + vlast->next = vfirst; + + for(auto i : IntRange(1,n)) + new_verts[n-1-i]->pnext = std::move(new_verts[n-i]); + + first = std::move(new_verts[0]); + } return *this; } + void Clear() + { + first = nullptr; + } + Vertex & AppendVertex(const Vertex & v) { auto & vnew = Append( static_cast>(v), true ); @@ -448,6 +488,8 @@ struct Loop } bool IsInside( Point<2> r ) const; + bool IsLeftInside( const Vertex & p0 ); + bool IsRightInside( const Vertex & p0 ); EdgeIterator Edges(IteratorType iterType) const { @@ -551,6 +593,8 @@ struct Loop return cnt; } + + netgen::Box<2> GetBoundingBox() const; }; @@ -563,12 +607,15 @@ struct Solid2d Solid2d() = default; Solid2d(string name_) : name(name_) {} DLL_HEADER Solid2d(const Array, EdgeInfo>> & points, string name_=MAT_DEFAULT, string bc_=BC_DEFAULT); + Solid2d(Solid2d && other) = default; + Solid2d(const Solid2d & other) = default; DLL_HEADER Solid2d operator+(const Solid2d & other) const; DLL_HEADER Solid2d operator*(const Solid2d & other) const; DLL_HEADER Solid2d operator-(const Solid2d & other) const; - DLL_HEADER Solid2d& operator=(const Solid2d & other) = default; + Solid2d& operator=(Solid2d && other) = default; + Solid2d& operator=(const Solid2d & other) = default; DLL_HEADER Solid2d& operator+=(const Solid2d & other); DLL_HEADER Solid2d& operator*=(const Solid2d & other); DLL_HEADER Solid2d& operator-=(const Solid2d & other); @@ -632,7 +679,7 @@ struct Solid2d return *this; } - netgen::Box<2> GetBoundingBox(); + netgen::Box<2> GetBoundingBox() const; }; @@ -654,7 +701,12 @@ DLL_HEADER Solid2d Circle( Point<2> center, double r, string name="", string bc= DLL_HEADER Solid2d Rectangle( Point<2> p0, Point<2> p1, string mat=MAT_DEFAULT, string bc=BC_DEFAULT ); DLL_HEADER void AddIntersectionPoints ( Solid2d & s1, Solid2d & s2 ); -DLL_HEADER Solid2d ClipSolids ( Solid2d s1, Solid2d s2, bool intersect=true ); +DLL_HEADER Solid2d ClipSolids ( const Solid2d & s1, const Solid2d & s2, char op); +DLL_HEADER Solid2d ClipSolids ( const Solid2d & s1, Solid2d && s2, char op); +DLL_HEADER Solid2d ClipSolids ( Solid2d && s1, const Solid2d & s2, char op); +DLL_HEADER Solid2d ClipSolids ( Solid2d && s1, Solid2d && s2, char op); + +DLL_HEADER IntersectionType intersect(const Point<2> P1, const Point<2> P2, const Point<2> Q1, const Point<2> Q2, double& alpha, double& beta); } #endif // NETGEN_CSG2D_HPP_INCLUDED From f55e3e6eb4c32477305ef0901399e0cabd412cf4 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Wed, 14 Oct 2020 12:00:37 +0200 Subject: [PATCH 190/384] move DelaunayTree to adtree.hpp --- libsrc/gprim/adtree.hpp | 278 +++++++++++++++++++++++++++++++++++ libsrc/meshing/delaunay.cpp | 279 ------------------------------------ 2 files changed, 278 insertions(+), 279 deletions(-) diff --git a/libsrc/gprim/adtree.hpp b/libsrc/gprim/adtree.hpp index bff29157..f05f7170 100644 --- a/libsrc/gprim/adtree.hpp +++ b/libsrc/gprim/adtree.hpp @@ -1099,6 +1099,284 @@ public: // auto & Tree() { return *tree; }; // }; + template + class DelaunayTree + { + public: + // Number of entries per leaf + static constexpr int N = 100; + + struct Node; + + struct Leaf + { + Point<2*dim, TSCAL> p[N]; + T index[N]; + int n_elements; + int nr; + + Leaf() : n_elements(0) + { } + + + void Add( Array &leaves, Array &leaf_index, const Point<2*dim> &ap, T aindex ) + { + p[n_elements] = ap; + index[n_elements] = aindex; + n_elements++; + if(leaf_index.Size() leaves; + Array leaf_index; + + Point global_min, global_max; + double tol; + size_t n_leaves; + size_t n_nodes; + BlockAllocator ball_nodes; + BlockAllocator ball_leaves; + + public: + + DelaunayTree (const Point & pmin, const Point & pmax) + : global_min(pmin), global_max(pmax), n_leaves(1), n_nodes(1), ball_nodes(sizeof(Node)), ball_leaves(sizeof(Leaf)) + { + root.leaf = (Leaf*) ball_leaves.Alloc(); new (root.leaf) Leaf(); + root.leaf->nr = 0; + leaves.Append(root.leaf); + root.level = 0; + tol = 1e-7 * Dist(pmax, pmin); + } + + DelaunayTree (const Box & box) + : DelaunayTree(box.PMin(), box.PMax()) + { } + + size_t GetNLeaves() + { + return n_leaves; + } + + size_t GetNNodes() + { + return n_nodes; + } + + template + void GetFirstIntersecting (const Point & pmin, const Point & pmax, + TFunc func=[](auto pi){return false;}) const + { + // static Timer timer("DelaunayTree::GetIntersecting"); RegionTimer rt(timer); + // static Timer timer1("DelaunayTree::GetIntersecting-LinearSearch"); + ArrayMem stack; + ArrayMem dir_stack; + + + Point<2*dim> tpmin, tpmax; + + for (size_t i : IntRange(dim)) + { + tpmin(i) = global_min(i); + tpmax(i) = pmax(i)+tol; + + tpmin(i+dim) = pmin(i)-tol; + tpmax(i+dim) = global_max(i); + } + + stack.SetSize(0); + stack.Append(&root); + dir_stack.SetSize(0); + dir_stack.Append(0); + + while(stack.Size()) + { + const Node *node = stack.Last(); + stack.DeleteLast(); + + int dir = dir_stack.Last(); + dir_stack.DeleteLast(); + + if(Leaf *leaf = node->GetLeaf()) + { + // RegionTimer rt1(timer1); + for (auto i : IntRange(leaf->n_elements)) + { + bool intersect = true; + const auto p = leaf->p[i]; + + for (int d = 0; d < dim; d++) + if (p[d] > tpmax[d]) + intersect = false; + for (int d = dim; d < 2*dim; d++) + if (p[d] < tpmin[d]) + intersect = false; + if(intersect) + if(func(leaf->index[i])) return; + } + } + else + { + int newdir = dir+1; + if(newdir==2*dim) newdir = 0; + if (tpmin[dir] <= node->sep) + { + stack.Append(node->children[0]); + dir_stack.Append(newdir); + } + if (tpmax[dir] >= node->sep) + { + stack.Append(node->children[1]); + dir_stack.Append(newdir); + } + } + } + } + + void GetIntersecting (const Point & pmin, const Point & pmax, + NgArray & pis) const + { + pis.SetSize(0); + GetFirstIntersecting(pmin, pmax, [&pis](auto pi) { pis.Append(pi); return false;}); + } + + void Insert (const Box & box, T pi) + { + Insert (box.PMin(), box.PMax(), pi); + } + + void Insert (const Point & pmin, const Point & pmax, T pi) + { + // static Timer timer("DelaunayTree::Insert"); RegionTimer rt(timer); + int dir = 0; + Point<2*dim> p; + for (auto i : IntRange(dim)) + { + p(i) = pmin[i]; + p(i+dim) = pmax[i]; + } + + Node * node = &root; + Leaf * leaf = node->GetLeaf(); + + // search correct leaf to add point + while(!leaf) + { + node = p[dir] < node->sep ? node->children[0] : node->children[1]; + dir++; + if(dir==2*dim) dir = 0; + leaf = node->GetLeaf(); + } + + // add point to leaf + if(leaf->n_elements < N) + leaf->Add(leaves, leaf_index, p,pi); + else // assume leaf->n_elements == N + { + // add two new nodes and one new leaf + int n_elements = leaf->n_elements; + ArrayMem coords(n_elements); + ArrayMem order(n_elements); + + // separate points in two halves, first sort all coordinates in direction dir + for (auto i : IntRange(n_elements)) + { + order[i] = i; + coords[i] = leaf->p[i][dir]; + } + + QuickSortI(coords, order); + int isplit = N/2; + Leaf *leaf1 = (Leaf*) ball_leaves.Alloc(); new (leaf1) Leaf(); + Leaf *leaf2 = (Leaf*) ball_leaves.Alloc(); new (leaf2) Leaf(); + + leaf1->nr = leaf->nr; + leaf2->nr = leaves.Size(); + leaves.Append(leaf2); + leaves[leaf1->nr] = leaf1; + + for (auto i : order.Range(isplit)) + leaf1->Add(leaves, leaf_index, leaf->p[i], leaf->index[i] ); + for (auto i : order.Range(isplit, N)) + leaf2->Add(leaves, leaf_index, leaf->p[i], leaf->index[i] ); + + Node *node1 = (Node*) ball_nodes.Alloc(); new (node1) Node(); + node1->leaf = leaf1; + node1->level = node->level+1; + + Node *node2 = (Node*) ball_nodes.Alloc(); new (node2) Node(); + node2->leaf = leaf2; + node2->level = node->level+1; + + node->children[0] = node1; + node->children[1] = node2; + node->sep = 0.5 * (leaf->p[order[isplit-1]][dir] + leaf->p[order[isplit]][dir]); + + // add new point to one of the new leaves + if (p[dir] < node->sep) + leaf1->Add( leaves, leaf_index, p, pi ); + else + leaf2->Add( leaves, leaf_index, p, pi ); + + ball_leaves.Free(leaf); + n_leaves++; + n_nodes+=2; + } + } + + void DeleteElement (T pi) + { + // static Timer timer("DelaunayTree::DeleteElement"); RegionTimer rt(timer); + Leaf *leaf = leaves[leaf_index[pi]]; + leaf_index[pi] = -1; + auto & n_elements = leaf->n_elements; + auto & index = leaf->index; + auto & p = leaf->p; + + for (auto i : IntRange(n_elements)) + { + if(index[i] == pi) + { + n_elements--; + if(i!=n_elements) + { + index[i] = index[n_elements]; + p[i] = p[n_elements]; + } + return; + } + } + } + }; } #endif diff --git a/libsrc/meshing/delaunay.cpp b/libsrc/meshing/delaunay.cpp index a152b762..adc64712 100644 --- a/libsrc/meshing/delaunay.cpp +++ b/libsrc/meshing/delaunay.cpp @@ -3,285 +3,6 @@ namespace netgen { - template - class DelaunayTree - { - public: - // Number of entries per leaf - static constexpr int N = 100; - - struct Node; - - struct Leaf - { - Point<2*dim, TSCAL> p[N]; - T index[N]; - int n_elements; - int nr; - - Leaf() : n_elements(0) - { } - - - void Add( Array &leaves, Array &leaf_index, const Point<2*dim> &ap, T aindex ) - { - p[n_elements] = ap; - index[n_elements] = aindex; - n_elements++; - if(leaf_index.Size() leaves; - Array leaf_index; - - Point global_min, global_max; - double tol; - size_t n_leaves; - size_t n_nodes; - BlockAllocator ball_nodes; - BlockAllocator ball_leaves; - - public: - - DelaunayTree (const Point & pmin, const Point & pmax) - : global_min(pmin), global_max(pmax), n_leaves(1), n_nodes(1), ball_nodes(sizeof(Node)), ball_leaves(sizeof(Leaf)) - { - root.leaf = (Leaf*) ball_leaves.Alloc(); new (root.leaf) Leaf(); - root.leaf->nr = 0; - leaves.Append(root.leaf); - root.level = 0; - tol = 1e-7 * Dist(pmax, pmin); - } - - DelaunayTree (const Box & box) - : DelaunayTree(box.PMin(), box.PMax()) - { } - - size_t GetNLeaves() - { - return n_leaves; - } - - size_t GetNNodes() - { - return n_nodes; - } - - template - void GetFirstIntersecting (const Point & pmin, const Point & pmax, - TFunc func=[](auto pi){return false;}) const - { - // static Timer timer("DelaunayTree::GetIntersecting"); RegionTimer rt(timer); - // static Timer timer1("DelaunayTree::GetIntersecting-LinearSearch"); - ArrayMem stack; - ArrayMem dir_stack; - - - Point<2*dim> tpmin, tpmax; - - for (size_t i : IntRange(dim)) - { - tpmin(i) = global_min(i); - tpmax(i) = pmax(i)+tol; - - tpmin(i+dim) = pmin(i)-tol; - tpmax(i+dim) = global_max(i); - } - - stack.SetSize(0); - stack.Append(&root); - dir_stack.SetSize(0); - dir_stack.Append(0); - - while(stack.Size()) - { - const Node *node = stack.Last(); - stack.DeleteLast(); - - int dir = dir_stack.Last(); - dir_stack.DeleteLast(); - - if(Leaf *leaf = node->GetLeaf()) - { - // RegionTimer rt1(timer1); - for (auto i : IntRange(leaf->n_elements)) - { - bool intersect = true; - const auto p = leaf->p[i]; - - for (int d = 0; d < dim; d++) - if (p[d] > tpmax[d]) - intersect = false; - for (int d = dim; d < 2*dim; d++) - if (p[d] < tpmin[d]) - intersect = false; - if(intersect) - if(func(leaf->index[i])) return; - } - } - else - { - int newdir = dir+1; - if(newdir==2*dim) newdir = 0; - if (tpmin[dir] <= node->sep) - { - stack.Append(node->children[0]); - dir_stack.Append(newdir); - } - if (tpmax[dir] >= node->sep) - { - stack.Append(node->children[1]); - dir_stack.Append(newdir); - } - } - } - } - - void GetIntersecting (const Point & pmin, const Point & pmax, - NgArray & pis) const - { - pis.SetSize(0); - GetFirstIntersecting(pmin, pmax, [&pis](auto pi) { pis.Append(pi); return false;}); - } - - void Insert (const Box & box, T pi) - { - Insert (box.PMin(), box.PMax(), pi); - } - - void Insert (const Point & pmin, const Point & pmax, T pi) - { - // static Timer timer("DelaunayTree::Insert"); RegionTimer rt(timer); - int dir = 0; - Point<2*dim> p; - for (auto i : IntRange(dim)) - { - p(i) = pmin[i]; - p(i+dim) = pmax[i]; - } - - Node * node = &root; - Leaf * leaf = node->GetLeaf(); - - // search correct leaf to add point - while(!leaf) - { - node = p[dir] < node->sep ? node->children[0] : node->children[1]; - dir++; - if(dir==2*dim) dir = 0; - leaf = node->GetLeaf(); - } - - // add point to leaf - if(leaf->n_elements < N) - leaf->Add(leaves, leaf_index, p,pi); - else // assume leaf->n_elements == N - { - // add two new nodes and one new leaf - int n_elements = leaf->n_elements; - ArrayMem coords(n_elements); - ArrayMem order(n_elements); - - // separate points in two halves, first sort all coordinates in direction dir - for (auto i : IntRange(n_elements)) - { - order[i] = i; - coords[i] = leaf->p[i][dir]; - } - - QuickSortI(coords, order); - int isplit = N/2; - Leaf *leaf1 = (Leaf*) ball_leaves.Alloc(); new (leaf1) Leaf(); - Leaf *leaf2 = (Leaf*) ball_leaves.Alloc(); new (leaf2) Leaf(); - - leaf1->nr = leaf->nr; - leaf2->nr = leaves.Size(); - leaves.Append(leaf2); - leaves[leaf1->nr] = leaf1; - - for (auto i : order.Range(isplit)) - leaf1->Add(leaves, leaf_index, leaf->p[i], leaf->index[i] ); - for (auto i : order.Range(isplit, N)) - leaf2->Add(leaves, leaf_index, leaf->p[i], leaf->index[i] ); - - Node *node1 = (Node*) ball_nodes.Alloc(); new (node1) Node(); - node1->leaf = leaf1; - node1->level = node->level+1; - - Node *node2 = (Node*) ball_nodes.Alloc(); new (node2) Node(); - node2->leaf = leaf2; - node2->level = node->level+1; - - node->children[0] = node1; - node->children[1] = node2; - node->sep = 0.5 * (leaf->p[order[isplit-1]][dir] + leaf->p[order[isplit]][dir]); - - // add new point to one of the new leaves - if (p[dir] < node->sep) - leaf1->Add( leaves, leaf_index, p, pi ); - else - leaf2->Add( leaves, leaf_index, p, pi ); - - ball_leaves.Free(leaf); - n_leaves++; - n_nodes+=2; - } - } - - void DeleteElement (T pi) - { - // static Timer timer("DelaunayTree::DeleteElement"); RegionTimer rt(timer); - Leaf *leaf = leaves[leaf_index[pi]]; - leaf_index[pi] = -1; - auto & n_elements = leaf->n_elements; - auto & index = leaf->index; - auto & p = leaf->p; - - for (auto i : IntRange(n_elements)) - { - if(index[i] == pi) - { - n_elements--; - if(i!=n_elements) - { - index[i] = index[n_elements]; - p[i] = p[n_elements]; - } - return; - } - } - } - }; - // typedef BoxTree<3> DTREE; typedef DelaunayTree<3> DTREE; From 476a4c350cc9ba9bcfff030a24ba6ca4e2732e9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20Sch=C3=B6berl?= Date: Wed, 14 Oct 2020 16:36:27 +0200 Subject: [PATCH 191/384] robust Polyhedron::VecInSolid option --- libsrc/csg/polyhedra.cpp | 157 +++++++++++++++++++++++++---------- libsrc/gprim/geomobjects.hpp | 12 ++- 2 files changed, 123 insertions(+), 46 deletions(-) diff --git a/libsrc/csg/polyhedra.cpp b/libsrc/csg/polyhedra.cpp index 5e35241b..4bb93cdd 100644 --- a/libsrc/csg/polyhedra.cpp +++ b/libsrc/csg/polyhedra.cpp @@ -100,64 +100,45 @@ INSOLID_TYPE Polyhedra :: BoxInSolid (const BoxSphere<3> & box) const } + // check how many faces a ray starting in p intersects INSOLID_TYPE Polyhedra :: PointInSolid (const Point<3> & p, double eps) const { - //(*testout) << "PointInSolid p " << p << " eps " << eps << endl; - //(*testout) << "bbox " << poly_bbox << endl; + if (!poly_bbox.IsIn (p, eps)) + return IS_OUTSIDE; - if((p(0) > poly_bbox.PMax()(0) + eps) || (p(0) < poly_bbox.PMin()(0) - eps) || - (p(1) > poly_bbox.PMax()(1) + eps) || (p(1) < poly_bbox.PMin()(1) - eps) || - (p(2) > poly_bbox.PMax()(2) + eps) || (p(2) < poly_bbox.PMin()(2) - eps)) - { - //(*testout) << "returning IS_OUTSIDE" << endl; - return IS_OUTSIDE; - } - - Vec<3> n, v1, v2; - - // random (?) numbers: - n(0) = -0.424621; - n(1) = 0.15432; - n(2) = 0.89212238; + // random (?) direction: + Vec<3> n(-0.424621, 0.1543, 0.89212238); int cnt = 0; - - for (int i = 0; i < faces.Size(); i++) + for (auto & face : faces) { - const Point<3> & p1 = points[faces[i].pnums[0]]; - - Vec<3> v0 = p - p1; + Vec<3> v0 = p - points[face.pnums[0]]; - double lam3 = faces[i].nn * v0; + double lam3 = face.nn * v0; - if(fabs(lam3) < eps) + if (fabs(lam3) < eps) // point is in plance of face { - double lam1 = (faces[i].w1 * v0); - double lam2 = (faces[i].w2 * v0); + double lam1 = face.w1 * v0; + double lam2 = face.w2 * v0; if (lam1 >= -eps_base1 && lam2 >= -eps_base1 && lam1+lam2 <= 1+eps_base1) - { - //(*testout) << "returning DOES_INTERSECT" << endl; - return DOES_INTERSECT; - } + return DOES_INTERSECT; } else { - lam3 = -(faces[i].n * v0) / (faces[i].n * n); + double lam3 = -(face.n * v0) / (face.n * n); - if (lam3 < 0) continue; + if (lam3 < 0) continue; // ray goes not in direction of face Vec<3> rs = v0 + lam3 * n; - double lam1 = (faces[i].w1 * rs); - double lam2 = (faces[i].w2 * rs); + double lam1 = face.w1 * rs; + double lam2 = face.w2 * rs; if (lam1 >= 0 && lam2 >= 0 && lam1+lam2 <= 1) cnt++; } - } - //(*testout) << " cnt = " << cnt%2 << endl; return (cnt % 2) ? IS_INSIDE : IS_OUTSIDE; } @@ -169,15 +150,16 @@ void Polyhedra :: GetTangentialSurfaceIndices (const Point<3> & p, { for (int i = 0; i < faces.Size(); i++) { - const Point<3> & p1 = points[faces[i].pnums[0]]; + auto & face = faces[i]; + const Point<3> & p1 = points[face.pnums[0]]; Vec<3> v0 = p - p1; - double lam3 = -(faces[i].nn * v0); // n->nn + double lam3 = -(face.nn * v0); // n->nn if (fabs (lam3) > eps) continue; - double lam1 = (faces[i].w1 * v0); - double lam2 = (faces[i].w2 * v0); + double lam1 = (face.w1 * v0); + double lam2 = (face.w2 * v0); if (lam1 >= -eps_base1 && lam2 >= -eps_base1 && lam1+lam2 <= 1+eps_base1) if (!surfind.Contains (GetSurfaceId(i))) @@ -186,8 +168,8 @@ void Polyhedra :: GetTangentialSurfaceIndices (const Point<3> & p, } - - +#define OLDVECINSOLD +#ifdef OLDVECINSOLD INSOLID_TYPE Polyhedra :: VecInSolid (const Point<3> & p, const Vec<3> & v, double eps) const @@ -250,17 +232,104 @@ INSOLID_TYPE Polyhedra :: VecInSolid (const Point<3> & p, } } - Point<3> p2 = p + (1e-2*mindist) * vn; + Point<3> p2 = p + (1e-4*mindist) * vn; res = PointInSolid (p2, eps); // (*testout) << "mindist " << mindist << " res " << res << endl; return res; - - } +#else + + // check how many faces a ray starting in p+alpha*v intersects +INSOLID_TYPE Polyhedra :: VecInSolid (const Point<3> & p, + const Vec<3> & v, + double eps) const +{ + if (!poly_bbox.IsIn (p, eps)) + return IS_OUTSIDE; + + // random (?) direction: + Vec<3> n(-0.424621, 0.1543, 0.89212238); + + int cnt = 0; + for (auto & face : faces) + { + Vec<3> v0 = p - points[face.pnums[0]]; + + double lamn = face.nn * v0; + + if (fabs(lamn) < eps) // point is in plance of face + { + double lam1 = face.w1 * v0; + double lam2 = face.w2 * v0; + double lam3 = 1-lam1-lam2; + + if (lam1 >= -eps_base1 && lam2 >= -eps_base1 && lam3 >= -eps_base1) + { // point is close to trianlge, perturbe by alpha*v + double dlamn = face.nn*v; + double dlam1 = face.w1 * v; + double dlam2 = face.w2 * v; + double dlam3 = 1-dlam1-dlam2; + + if (fabs(dlamn) < 1e-8) // vec also in plane + { + bool in1 = lam1 > eps_base1 || dlam1 > -eps_base1; + bool in2 = lam2 > eps_base1 || dlam2 > -eps_base1; + bool in3 = lam3 > eps_base1 || dlam3 > -eps_base1; + if (in1 && in2 && in3) + return DOES_INTERSECT; + } + else // vec out of plane + { + double dlamn = -(face.n * v) / (face.n * n); + if (dlamn < 0) continue; // ray goes not in direction of face + + Vec<3> drs = v0 + lamn * n; + + double dlam1 = dlamn * face.w1 * v; + double dlam2 = dlamn * face.w2 * v; + double dlam3 = 1-dlam1-dlam2; + + bool in1 = lam1 > eps_base1 || dlam1 > -eps_base1; + bool in2 = lam2 > eps_base1 || dlam2 > -eps_base1; + bool in3 = lam3 > eps_base1 || dlam3 > -eps_base1; + + if (in1 && in2 && in3) + cnt++; + } + } + } + else + { + double lamn = -(face.n * v0) / (face.n * n); + + if (lamn < 0) continue; // ray goes not in direction of face + + Vec<3> rs = v0 + lamn * n; + + double lam1 = face.w1 * rs; + double lam2 = face.w2 * rs; + double lam3 = 1-lam1-lam2; + if (lam1 >= 0 && lam2 >= 0 && lam3 >= 0) + cnt++; + } + } + + return (cnt % 2) ? IS_INSIDE : IS_OUTSIDE; +} + +#endif + + + + + + + + /* INSOLID_TYPE Polyhedra :: VecInSolid2 (const Point<3> & p, const Vec<3> & v1, diff --git a/libsrc/gprim/geomobjects.hpp b/libsrc/gprim/geomobjects.hpp index 48f74680..765565f0 100644 --- a/libsrc/gprim/geomobjects.hpp +++ b/libsrc/gprim/geomobjects.hpp @@ -384,8 +384,16 @@ namespace netgen bool IsIn (const Point & p) const { for (int i = 0; i < D; i++) - if (p(i) < pmin(i) || p(i) > pmax(i)) return 0; - return 1; + if (p(i) < pmin(i) || p(i) > pmax(i)) return false; + return true; + } + + // is point in eps-increased box + bool IsIn (const Point & p, double eps) const + { + for (int i = 0; i < D; i++) + if (p(i) < pmin(i)-eps || p(i) > pmax(i)+eps) return false; + return true; } From 7b8b3b03ca112c40e85ebaf82757ecce5d285e5c Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Wed, 14 Oct 2020 17:13:17 +0200 Subject: [PATCH 192/384] bounding box for Loop --- libsrc/geom2d/csg2d.cpp | 35 +++++++++++++++-------------------- libsrc/geom2d/csg2d.hpp | 22 ++++++++++++++++++++-- 2 files changed, 35 insertions(+), 22 deletions(-) diff --git a/libsrc/geom2d/csg2d.cpp b/libsrc/geom2d/csg2d.cpp index 20e021c6..e1168d53 100644 --- a/libsrc/geom2d/csg2d.cpp +++ b/libsrc/geom2d/csg2d.cpp @@ -670,13 +670,16 @@ void AddIntersectionPoint(Edge edgeP, Edge edgeQ, IntersectionType i, double alp } } - -void ComputeIntersections(Solid2d & sp, Solid2d & sq) +void ComputeIntersections(Solid2d & s1, Solid2d & s2) { static Timer tall("ComputeIntersections"); RegionTimer rtall(tall); - auto & PP = sp.polys; - auto & QQ = sq.polys; + static Timer t_tree("build search trees"); + static Timer t_intersect("find intersections"); + static Timer t_split("split splines"); + auto & PP = s1.polys; + auto & QQ = s2.polys; + t_intersect.Start(); for (Loop& P : PP) for (Edge edgeP : P.Edges(SOURCE)) for (Loop& Q : QQ) @@ -716,6 +719,9 @@ void ComputeIntersections(Solid2d & sp, Solid2d & sq) } } } + t_intersect.Stop(); + + RegionTimer rt_split(t_split); // Split splines at new vertices auto split_spline_at_vertex = [](Vertex *v) @@ -1351,25 +1357,21 @@ Solid2d ClipSolids ( Solid2d && s1, Solid2d && s2, char op) res_polys.SetSize(0); t02.Start(); - netgen::Box<2> s1_box(netgen::Box<2>::EMPTY_BOX); - netgen::BoxTree <2, int> tree1(s1.GetBoundingBox()); + auto s1_box = s1.GetBoundingBox(); + netgen::BoxTree <2, int> tree1(s1_box); for(auto li : IntRange(n1)) { auto box = s1.polys[li].GetBoundingBox(); - s1_box.Add(box.PMin()); - s1_box.Add(box.PMax()); tree1.Insert(box, li); } - netgen::Box<2> s2_box(netgen::Box<2>::EMPTY_BOX); + auto s2_box = s2.GetBoundingBox(); netgen::BoxTree <2, int> tree2(s2.GetBoundingBox()); for(auto li : IntRange(n2)) { auto box = s2.polys[li].GetBoundingBox(); - s2_box.Add(box.PMin()); - s2_box.Add(box.PMax()); tree2.Insert(box, li); } t02.Stop(); @@ -1529,15 +1531,6 @@ bool Loop :: IsInside( Point<2> r ) const return ( (w % 2) != 0 ); } -netgen::Box<2> Loop :: GetBoundingBox() const -{ - // static Timer tall("Loop::GetBoundingBox"); RegionTimer rtall(tall); - netgen::Box<2> box(netgen::Box<2>::EMPTY_BOX); - for(auto v : Vertices(ALL)) - box.Add(*v); - return box; -} - Solid2d :: Solid2d(const Array, EdgeInfo>> & points, string name_, string bc) : name(name_) @@ -1729,6 +1722,7 @@ shared_ptr CSG2d :: GenerateSplineGeometry() static Timer tall("CSG2d - GenerateSplineGeometry()"); static Timer t_points("add points"); static Timer t_segments_map("build segments map"); + static Timer t_is_inside("is inside check"); static Timer t_segments("add segments"); static Timer t_intersections("add intersections"); RegionTimer rt(tall); @@ -1861,6 +1855,7 @@ shared_ptr CSG2d :: GenerateSplineGeometry() if(first) { + RegionTimer rt_inside(t_is_inside); is_poly_left_inside = s.IsLeftInside(p0); is_poly_right_inside = s.IsRightInside(p0); first = true; diff --git a/libsrc/geom2d/csg2d.hpp b/libsrc/geom2d/csg2d.hpp index 938032ba..16175f1e 100644 --- a/libsrc/geom2d/csg2d.hpp +++ b/libsrc/geom2d/csg2d.hpp @@ -12,6 +12,7 @@ using namespace ngcore; using netgen::Point; using netgen::Vec; using Spline = SplineSeg3<2>; +using netgen::Box; inline double Area(const Point<2>& P, const Point<2>& Q, const Point<2>& R) { @@ -395,6 +396,7 @@ inline int CalcSide( const Point<2> & p0, const Point<2> & p1, const Point<2> & struct Loop { unique_ptr first = nullptr; + unique_ptr> bbox = nullptr; Loop() = default; @@ -440,6 +442,7 @@ struct Loop first = std::move(new_verts[0]); } + bbox = nullptr; return *this; } @@ -454,6 +457,8 @@ struct Loop vnew.info = v.info; if(v.spline) vnew.spline = *v.spline; + if(bbox) + bbox->Add(v); return vnew; } @@ -474,6 +479,8 @@ struct Loop vnew->is_source = source; // cout << "size after " << Size() << endl; + if(bbox) + bbox->Add(p); return *vnew; } @@ -485,6 +492,7 @@ struct Loop first = std::move(v->pnext); else v->prev->pnext = std::move(v->pnext); + bbox.reset(); } bool IsInside( Point<2> r ) const; @@ -594,7 +602,17 @@ struct Loop return cnt; } - netgen::Box<2> GetBoundingBox() const; + const Box<2> & GetBoundingBox() + { + if(bbox==nullptr) + { + static Timer tall("Loop::GetBoundingBox"); RegionTimer rt(tall); + bbox = make_unique>(Box<2>::EMPTY_BOX); + for(auto v : Vertices(ALL)) + bbox->Add(*v); + } + return *bbox; + } }; @@ -679,7 +697,7 @@ struct Solid2d return *this; } - netgen::Box<2> GetBoundingBox() const; + Box<2> GetBoundingBox() const; }; From 307c2a3bbbe5f340c0ae6833bc9579331e823de1 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Wed, 14 Oct 2020 18:40:23 +0200 Subject: [PATCH 193/384] CSG2d - faster AddIntersections (search tree per loop) --- libsrc/geom2d/csg2d.cpp | 146 +++++++++++++++++++++++----------------- 1 file changed, 85 insertions(+), 61 deletions(-) diff --git a/libsrc/geom2d/csg2d.cpp b/libsrc/geom2d/csg2d.cpp index e1168d53..f46a813d 100644 --- a/libsrc/geom2d/csg2d.cpp +++ b/libsrc/geom2d/csg2d.cpp @@ -670,55 +670,49 @@ void AddIntersectionPoint(Edge edgeP, Edge edgeQ, IntersectionType i, double alp } } -void ComputeIntersections(Solid2d & s1, Solid2d & s2) +void ComputeIntersections(Loop & l1, Loop & l2) { - static Timer tall("ComputeIntersections"); RegionTimer rtall(tall); - static Timer t_tree("build search trees"); static Timer t_intersect("find intersections"); static Timer t_split("split splines"); - auto & PP = s1.polys; - auto & QQ = s2.polys; t_intersect.Start(); - for (Loop& P : PP) - for (Edge edgeP : P.Edges(SOURCE)) - for (Loop& Q : QQ) - for (Edge edgeQ : Q.Edges(SOURCE)) + for (Edge edgeP : l1.Edges(SOURCE)) + for (Edge edgeQ : l2.Edges(SOURCE)) + { + double alpha = 0.0; + double beta = 0.0; + IntersectionType i = intersect(edgeP, edgeQ, alpha, beta); + AddIntersectionPoint(edgeP, edgeQ, i, alpha, beta); + if(i==X_INTERSECTION && (edgeP.v0->spline || edgeQ.v0->spline)) + { + double alpha1 = alpha+1e2*EPSILON; + double beta1 = 0.0; //beta+1e2*EPSILON; + + // search for possible second intersection + i = intersect(edgeP, edgeQ, alpha1, beta1); + // cout << "second intersection " << i << ',' << alpha1 << ',' << beta1 << ',' << alpha1-alpha << ',' << beta1-beta << endl; + if(i!=NO_INTERSECTION && alpha+EPSILONspline || edgeQ.v0->spline)) + // Add midpoint of two intersection points to avoid false overlap detection of splines + // TODO: Check if this is really necessary + auto alpha_mid = 0.5*(alpha+alpha1); + auto beta_mid = 0.5*(beta+beta1); + Point<2> MP; + if(edgeP.v0->spline) { - double alpha1 = alpha+1e2*EPSILON; - double beta1 = 0.0; //beta+1e2*EPSILON; - - // search for possible second intersection - i = intersect(edgeP, edgeQ, alpha1, beta1); - // cout << "second intersection " << i << ',' << alpha1 << ',' << beta1 << ',' << alpha1-alpha << ',' << beta1-beta << endl; - if(i!=NO_INTERSECTION && alpha+EPSILON MP; - if(edgeP.v0->spline) - { - MP = edgeP.v0->spline->GetPoint(alpha_mid); - edgeP.v0->Insert(MP, alpha_mid); - } - else - MP = edgeQ.v0->spline->GetPoint(beta_mid); - - if(edgeQ.v0->spline) - edgeQ.v0->Insert(MP, beta_mid); - - AddIntersectionPoint(edgeP, edgeQ, i, alpha1, beta1); - } + MP = edgeP.v0->spline->GetPoint(alpha_mid); + edgeP.v0->Insert(MP, alpha_mid); } + else + MP = edgeQ.v0->spline->GetPoint(beta_mid); + + if(edgeQ.v0->spline) + edgeQ.v0->Insert(MP, beta_mid); + + AddIntersectionPoint(edgeP, edgeQ, i, alpha1, beta1); } + } + } t_intersect.Stop(); RegionTimer rt_split(t_split); @@ -743,12 +737,19 @@ void ComputeIntersections(Solid2d & s1, Solid2d & s2) } while(!curr->is_source); }; - for (Loop& P : PP) - for (Vertex* v : P.Vertices(SOURCE)) - split_spline_at_vertex(v); - for (Loop& Q : QQ) - for (Vertex* v : Q.Vertices(SOURCE)) - split_spline_at_vertex(v); + for (Vertex* v : l1.Vertices(SOURCE)) + split_spline_at_vertex(v); + for (Vertex* v : l2.Vertices(SOURCE)) + split_spline_at_vertex(v); +} + +void ComputeIntersections(Solid2d & s1, Solid2d & s2) +{ + static Timer tall("ComputeIntersections"); RegionTimer rtall(tall); + + for (Loop& l1 : s1.polys) + for (Loop& l2 : s2.polys) + ComputeIntersections(l1, l2); } enum RelativePositionType @@ -1251,20 +1252,25 @@ void CleanUpResult(Solid2d & sr) RR.RemoveElement(i); } +void RemoveDuplicates(Loop & poly) +{ + if(poly.first==nullptr) + return; + + Vertex * last = poly.first->prev; + for(auto v : poly.Vertices(ALL)) + { + if(Dist2(*v, *last)prev; - for(auto v : poly.Vertices(ALL)) - { - if(Dist2(*v, *last) CSG2d :: GenerateSplineGeometry() static Timer t_is_inside("is inside check"); static Timer t_segments("add segments"); static Timer t_intersections("add intersections"); + static Timer t_segtree("seg trees"); RegionTimer rt(tall); struct Seg @@ -1756,18 +1771,27 @@ shared_ptr CSG2d :: GenerateSplineGeometry() box.Add(sbox.PMax()); } - netgen::BoxTree <2, int> solid_tree(box); + netgen::BoxTree <2> solid_tree(box); + Array> loop_list; for(auto i : Range(solids)) - solid_tree.Insert(solids[i].GetBoundingBox(), i); + for(auto li : Range(solids[i].polys)) + { + solid_tree.Insert(solids[i].polys[li].GetBoundingBox(), loop_list.Size()); + loop_list.Append(INT<2>(i, li)); + } for(auto i1 : Range(solids)) + for(auto li1 : Range(solids[i1].polys)) { - auto sbox = solids[i1].GetBoundingBox(); - solid_tree.GetFirstIntersecting(sbox.PMin(), sbox.PMax(), [&] (int i2) + auto & poly1 = solids[i1].polys[li1]; + auto box = poly1.GetBoundingBox(); + solid_tree.GetFirstIntersecting(box.PMin(), box.PMax(), [&] (int ii) { + auto i2 = loop_list[ii][0]; + auto li2 = loop_list[ii][1]; if(i1 Date: Wed, 14 Oct 2020 19:00:44 +0200 Subject: [PATCH 194/384] allow visualizing smaller tangent points --- ng/dialog.tcl | 2 +- ng/onetcl.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ng/dialog.tcl b/ng/dialog.tcl index 8c0bf730..1d7a65c2 100644 --- a/ng/dialog.tcl +++ b/ng/dialog.tcl @@ -1436,7 +1436,7 @@ proc viewingoptionsdialog { } { #pack $f.f1 -pady 5 -anchor center ttk::label $f.center.lab1 -text "SpecPoint Veclen" ttk::entry $f.center.ent1 -width 5 -textvariable viewoptions.specpointvlen -validate focus \ - -validatecommand "my_validate %W 0 1e9 %P 1" \ + -validatecommand "my_validate %W 0 1e9 %P 4" \ -invalidcommand "my_invalid %W" grid $f.center.ent1 $f.center.lab1 -sticky nw -padx 4 diff --git a/ng/onetcl.cpp b/ng/onetcl.cpp index bb98f97f..c104b543 100644 --- a/ng/onetcl.cpp +++ b/ng/onetcl.cpp @@ -2316,7 +2316,7 @@ DLL_HEADER const char * ngscript[] = {"" ,"grid $f.center.ent $f.center.btn -sticky nw -padx 4\n" ,"ttk::label $f.center.lab1 -text \"SpecPoint Veclen\"\n" ,"ttk::entry $f.center.ent1 -width 5 -textvariable viewoptions.specpointvlen -validate focus \\\n" -,"-validatecommand \"my_validate %W 0 1e9 %P 1\" \\\n" +,"-validatecommand \"my_validate %W 0 1e9 %P 4\" \\\n" ,"-invalidcommand \"my_invalid %W\"\n" ,"grid $f.center.ent1 $f.center.lab1 -sticky nw -padx 4\n" ,"set f $w.nb.misc\n" From 7a8e10738b25719ed218e8bc0d276a8a831fde4b Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Wed, 14 Oct 2020 19:59:36 +0200 Subject: [PATCH 195/384] Revert "CSG2d - faster AddIntersections (search tree per loop)" This reverts commit 307c2a3bbbe5f340c0ae6833bc9579331e823de1. --- libsrc/geom2d/csg2d.cpp | 146 +++++++++++++++++----------------------- 1 file changed, 61 insertions(+), 85 deletions(-) diff --git a/libsrc/geom2d/csg2d.cpp b/libsrc/geom2d/csg2d.cpp index f46a813d..e1168d53 100644 --- a/libsrc/geom2d/csg2d.cpp +++ b/libsrc/geom2d/csg2d.cpp @@ -670,49 +670,55 @@ void AddIntersectionPoint(Edge edgeP, Edge edgeQ, IntersectionType i, double alp } } -void ComputeIntersections(Loop & l1, Loop & l2) +void ComputeIntersections(Solid2d & s1, Solid2d & s2) { + static Timer tall("ComputeIntersections"); RegionTimer rtall(tall); + static Timer t_tree("build search trees"); static Timer t_intersect("find intersections"); static Timer t_split("split splines"); + auto & PP = s1.polys; + auto & QQ = s2.polys; t_intersect.Start(); - for (Edge edgeP : l1.Edges(SOURCE)) - for (Edge edgeQ : l2.Edges(SOURCE)) - { - double alpha = 0.0; - double beta = 0.0; - IntersectionType i = intersect(edgeP, edgeQ, alpha, beta); - AddIntersectionPoint(edgeP, edgeQ, i, alpha, beta); - if(i==X_INTERSECTION && (edgeP.v0->spline || edgeQ.v0->spline)) - { - double alpha1 = alpha+1e2*EPSILON; - double beta1 = 0.0; //beta+1e2*EPSILON; - - // search for possible second intersection - i = intersect(edgeP, edgeQ, alpha1, beta1); - // cout << "second intersection " << i << ',' << alpha1 << ',' << beta1 << ',' << alpha1-alpha << ',' << beta1-beta << endl; - if(i!=NO_INTERSECTION && alpha+EPSILON MP; - if(edgeP.v0->spline) + double alpha = 0.0; + double beta = 0.0; + IntersectionType i = intersect(edgeP, edgeQ, alpha, beta); + AddIntersectionPoint(edgeP, edgeQ, i, alpha, beta); + if(i==X_INTERSECTION && (edgeP.v0->spline || edgeQ.v0->spline)) { - MP = edgeP.v0->spline->GetPoint(alpha_mid); - edgeP.v0->Insert(MP, alpha_mid); + double alpha1 = alpha+1e2*EPSILON; + double beta1 = 0.0; //beta+1e2*EPSILON; + + // search for possible second intersection + i = intersect(edgeP, edgeQ, alpha1, beta1); + // cout << "second intersection " << i << ',' << alpha1 << ',' << beta1 << ',' << alpha1-alpha << ',' << beta1-beta << endl; + if(i!=NO_INTERSECTION && alpha+EPSILON MP; + if(edgeP.v0->spline) + { + MP = edgeP.v0->spline->GetPoint(alpha_mid); + edgeP.v0->Insert(MP, alpha_mid); + } + else + MP = edgeQ.v0->spline->GetPoint(beta_mid); + + if(edgeQ.v0->spline) + edgeQ.v0->Insert(MP, beta_mid); + + AddIntersectionPoint(edgeP, edgeQ, i, alpha1, beta1); + } } - else - MP = edgeQ.v0->spline->GetPoint(beta_mid); - - if(edgeQ.v0->spline) - edgeQ.v0->Insert(MP, beta_mid); - - AddIntersectionPoint(edgeP, edgeQ, i, alpha1, beta1); } - } - } t_intersect.Stop(); RegionTimer rt_split(t_split); @@ -737,19 +743,12 @@ void ComputeIntersections(Loop & l1, Loop & l2) } while(!curr->is_source); }; - for (Vertex* v : l1.Vertices(SOURCE)) - split_spline_at_vertex(v); - for (Vertex* v : l2.Vertices(SOURCE)) - split_spline_at_vertex(v); -} - -void ComputeIntersections(Solid2d & s1, Solid2d & s2) -{ - static Timer tall("ComputeIntersections"); RegionTimer rtall(tall); - - for (Loop& l1 : s1.polys) - for (Loop& l2 : s2.polys) - ComputeIntersections(l1, l2); + for (Loop& P : PP) + for (Vertex* v : P.Vertices(SOURCE)) + split_spline_at_vertex(v); + for (Loop& Q : QQ) + for (Vertex* v : Q.Vertices(SOURCE)) + split_spline_at_vertex(v); } enum RelativePositionType @@ -1252,25 +1251,20 @@ void CleanUpResult(Solid2d & sr) RR.RemoveElement(i); } -void RemoveDuplicates(Loop & poly) -{ - if(poly.first==nullptr) - return; - - Vertex * last = poly.first->prev; - for(auto v : poly.Vertices(ALL)) - { - if(Dist2(*v, *last)prev; + for(auto v : poly.Vertices(ALL)) + { + if(Dist2(*v, *last) CSG2d :: GenerateSplineGeometry() static Timer t_is_inside("is inside check"); static Timer t_segments("add segments"); static Timer t_intersections("add intersections"); - static Timer t_segtree("seg trees"); RegionTimer rt(tall); struct Seg @@ -1771,27 +1756,18 @@ shared_ptr CSG2d :: GenerateSplineGeometry() box.Add(sbox.PMax()); } - netgen::BoxTree <2> solid_tree(box); - Array> loop_list; + netgen::BoxTree <2, int> solid_tree(box); for(auto i : Range(solids)) - for(auto li : Range(solids[i].polys)) - { - solid_tree.Insert(solids[i].polys[li].GetBoundingBox(), loop_list.Size()); - loop_list.Append(INT<2>(i, li)); - } + solid_tree.Insert(solids[i].GetBoundingBox(), i); for(auto i1 : Range(solids)) - for(auto li1 : Range(solids[i1].polys)) { - auto & poly1 = solids[i1].polys[li1]; - auto box = poly1.GetBoundingBox(); - solid_tree.GetFirstIntersecting(box.PMin(), box.PMax(), [&] (int ii) + auto sbox = solids[i1].GetBoundingBox(); + solid_tree.GetFirstIntersecting(sbox.PMin(), sbox.PMax(), [&] (int i2) { - auto i2 = loop_list[ii][0]; - auto li2 = loop_list[ii][1]; if(i1 Date: Thu, 15 Oct 2020 09:29:36 +0200 Subject: [PATCH 196/384] VecInSolid, poly --- libsrc/csg/polyhedra.cpp | 1244 ++++++++++++++++++++------------------ libsrc/csg/polyhedra.hpp | 8 + 2 files changed, 657 insertions(+), 595 deletions(-) diff --git a/libsrc/csg/polyhedra.cpp b/libsrc/csg/polyhedra.cpp index 4bb93cdd..c123458b 100644 --- a/libsrc/csg/polyhedra.cpp +++ b/libsrc/csg/polyhedra.cpp @@ -6,322 +6,376 @@ namespace netgen { -Polyhedra::Face::Face (int pi1, int pi2, int pi3, - const NgArray > & points, - int ainputnr) -{ - inputnr = ainputnr; + Polyhedra::Face::Face (int pi1, int pi2, int pi3, + const NgArray > & points, + int ainputnr) + { + inputnr = ainputnr; - pnums[0] = pi1; - pnums[1] = pi2; - pnums[2] = pi3; + pnums[0] = pi1; + pnums[1] = pi2; + pnums[2] = pi3; - bbox.Set (points[pi1]); - bbox.Add (points[pi2]); - bbox.Add (points[pi3]); + bbox.Set (points[pi1]); + bbox.Add (points[pi2]); + bbox.Add (points[pi3]); - v1 = points[pi2] - points[pi1]; - v2 = points[pi3] - points[pi1]; + v1 = points[pi2] - points[pi1]; + v2 = points[pi3] - points[pi1]; - n = Cross (v1, v2); + n = Cross (v1, v2); - nn = n; - nn.Normalize(); - // PseudoInverse (v1, v2, w1, w2); + nn = n; + nn.Normalize(); + // PseudoInverse (v1, v2, w1, w2); - Mat<2,3> mat; - Mat<3,2> inv; - for (int i = 0; i < 3; i++) - { - mat(0,i) = v1(i); - mat(1,i) = v2(i); - } - CalcInverse (mat, inv); - for (int i = 0; i < 3; i++) - { - w1(i) = inv(i,0); - w2(i) = inv(i,1); - } -} + Mat<2,3> mat; + Mat<3,2> inv; + for (int i = 0; i < 3; i++) + { + mat(0,i) = v1(i); + mat(1,i) = v2(i); + } + CalcInverse (mat, inv); + for (int i = 0; i < 3; i++) + { + w1(i) = inv(i,0); + w2(i) = inv(i,1); + } + } -Polyhedra :: Polyhedra () -{ - surfaceactive.SetSize(0); - surfaceids.SetSize(0); - eps_base1 = 1e-8; -} + Polyhedra :: Polyhedra () + { + surfaceactive.SetSize(0); + surfaceids.SetSize(0); + eps_base1 = 1e-8; + } -Polyhedra :: ~Polyhedra () -{ - ; -} + Polyhedra :: ~Polyhedra () + { + ; + } -Primitive * Polyhedra :: CreateDefault () -{ - return new Polyhedra(); -} + Primitive * Polyhedra :: CreateDefault () + { + return new Polyhedra(); + } -INSOLID_TYPE Polyhedra :: BoxInSolid (const BoxSphere<3> & box) const -{ - /* - for (i = 1; i <= faces.Size(); i++) - if (FaceBoxIntersection (i, box)) + INSOLID_TYPE Polyhedra :: BoxInSolid (const BoxSphere<3> & box) const + { + /* + for (i = 1; i <= faces.Size(); i++) + if (FaceBoxIntersection (i, box)) return DOES_INTERSECT; - */ - for (int i = 0; i < faces.Size(); i++) - { - if (!faces[i].bbox.Intersect (box)) - continue; - //(*testout) << "face " << i << endl; + */ + for (int i = 0; i < faces.Size(); i++) + { + if (!faces[i].bbox.Intersect (box)) + continue; + //(*testout) << "face " << i << endl; - const Point<3> & p1 = points[faces[i].pnums[0]]; - const Point<3> & p2 = points[faces[i].pnums[1]]; - const Point<3> & p3 = points[faces[i].pnums[2]]; + const Point<3> & p1 = points[faces[i].pnums[0]]; + const Point<3> & p2 = points[faces[i].pnums[1]]; + const Point<3> & p3 = points[faces[i].pnums[2]]; - if (fabs (faces[i].nn * (p1 - box.Center())) > box.Diam()/2) - continue; + if (fabs (faces[i].nn * (p1 - box.Center())) > box.Diam()/2) + continue; - //(*testout) << "still in loop" << endl; + //(*testout) << "still in loop" << endl; - double dist2 = MinDistTP2 (p1, p2, p3, box.Center()); - //(*testout) << "p1 " << p1 << " p2 " << p2 << " p3 " << p3 << endl - // << " box.Center " << box.Center() << " box.Diam() " << box.Diam() << endl - // << " dist2 " << dist2 << " sqr(box.Diam()/2) " << sqr(box.Diam()/2) << endl; - if (dist2 < sqr (box.Diam()/2)) - { - //(*testout) << "DOES_INTERSECT" << endl; - return DOES_INTERSECT; - } - }; + double dist2 = MinDistTP2 (p1, p2, p3, box.Center()); + //(*testout) << "p1 " << p1 << " p2 " << p2 << " p3 " << p3 << endl + // << " box.Center " << box.Center() << " box.Diam() " << box.Diam() << endl + // << " dist2 " << dist2 << " sqr(box.Diam()/2) " << sqr(box.Diam()/2) << endl; + if (dist2 < sqr (box.Diam()/2)) + { + //(*testout) << "DOES_INTERSECT" << endl; + return DOES_INTERSECT; + } + }; - return PointInSolid (box.Center(), 1e-3 * box.Diam()); -} + return PointInSolid (box.Center(), 1e-3 * box.Diam()); + } // check how many faces a ray starting in p intersects -INSOLID_TYPE Polyhedra :: PointInSolid (const Point<3> & p, - double eps) const -{ - if (!poly_bbox.IsIn (p, eps)) - return IS_OUTSIDE; + INSOLID_TYPE Polyhedra :: PointInSolid (const Point<3> & p, + double eps) const + { + if (!poly_bbox.IsIn (p, eps)) + return IS_OUTSIDE; - // random (?) direction: - Vec<3> n(-0.424621, 0.1543, 0.89212238); + // random (?) direction: + Vec<3> n(-0.424621, 0.1543, 0.89212238); - int cnt = 0; - for (auto & face : faces) - { - Vec<3> v0 = p - points[face.pnums[0]]; + int cnt = 0; + for (auto & face : faces) + { + Vec<3> v0 = p - points[face.pnums[0]]; - double lam3 = face.nn * v0; + double lam3 = face.nn * v0; - if (fabs(lam3) < eps) // point is in plance of face - { - double lam1 = face.w1 * v0; - double lam2 = face.w2 * v0; - if (lam1 >= -eps_base1 && lam2 >= -eps_base1 && lam1+lam2 <= 1+eps_base1) - return DOES_INTERSECT; - } - else - { - double lam3 = -(face.n * v0) / (face.n * n); + if (fabs(lam3) < eps) // point is in plance of face + { + double lam1 = face.w1 * v0; + double lam2 = face.w2 * v0; + if (lam1 >= -eps_base1 && lam2 >= -eps_base1 && lam1+lam2 <= 1+eps_base1) + return DOES_INTERSECT; + } + else + { + double lam3 = -(face.n * v0) / (face.n * n); - if (lam3 < 0) continue; // ray goes not in direction of face + if (lam3 < 0) continue; // ray goes not in direction of face - Vec<3> rs = v0 + lam3 * n; + Vec<3> rs = v0 + lam3 * n; - double lam1 = face.w1 * rs; - double lam2 = face.w2 * rs; - if (lam1 >= 0 && lam2 >= 0 && lam1+lam2 <= 1) - cnt++; - } - } + double lam1 = face.w1 * rs; + double lam2 = face.w2 * rs; + if (lam1 >= 0 && lam2 >= 0 && lam1+lam2 <= 1) + cnt++; + } + } - return (cnt % 2) ? IS_INSIDE : IS_OUTSIDE; -} + return (cnt % 2) ? IS_INSIDE : IS_OUTSIDE; + } -void Polyhedra :: GetTangentialSurfaceIndices (const Point<3> & p, - NgArray & surfind, double eps) const -{ - for (int i = 0; i < faces.Size(); i++) - { - auto & face = faces[i]; - const Point<3> & p1 = points[face.pnums[0]]; + void Polyhedra :: GetTangentialSurfaceIndices (const Point<3> & p, + NgArray & surfind, double eps) const + { + for (int i = 0; i < faces.Size(); i++) + { + auto & face = faces[i]; + const Point<3> & p1 = points[face.pnums[0]]; - Vec<3> v0 = p - p1; - double lam3 = -(face.nn * v0); // n->nn + Vec<3> v0 = p - p1; + double lam3 = -(face.nn * v0); // n->nn - if (fabs (lam3) > eps) continue; + if (fabs (lam3) > eps) continue; - double lam1 = (face.w1 * v0); - double lam2 = (face.w2 * v0); + double lam1 = (face.w1 * v0); + double lam2 = (face.w2 * v0); - if (lam1 >= -eps_base1 && lam2 >= -eps_base1 && lam1+lam2 <= 1+eps_base1) - if (!surfind.Contains (GetSurfaceId(i))) - surfind.Append (GetSurfaceId(i)); - } + if (lam1 >= -eps_base1 && lam2 >= -eps_base1 && lam1+lam2 <= 1+eps_base1) + if (!surfind.Contains (GetSurfaceId(i))) + surfind.Append (GetSurfaceId(i)); + } -} + } -#define OLDVECINSOLD -#ifdef OLDVECINSOLD -INSOLID_TYPE Polyhedra :: VecInSolid (const Point<3> & p, - const Vec<3> & v, - double eps) const -{ - NgArray point_on_faces; - INSOLID_TYPE res(DOES_INTERSECT); + INSOLID_TYPE Polyhedra :: VecInSolidOld (const Point<3> & p, + const Vec<3> & v, + double eps) const + { + NgArray point_on_faces; + INSOLID_TYPE res(DOES_INTERSECT); - Vec<3> vn = v; - vn.Normalize(); - for (int i = 0; i < faces.Size(); i++) - { - const Point<3> & p1 = points[faces[i].pnums[0]]; + Vec<3> vn = v; + vn.Normalize(); + for (int i = 0; i < faces.Size(); i++) + { + const Point<3> & p1 = points[faces[i].pnums[0]]; - Vec<3> v0 = p - p1; - double lam3 = -(faces[i].nn * v0); // n->nn + Vec<3> v0 = p - p1; + double lam3 = -(faces[i].nn * v0); // n->nn - if (fabs (lam3) > eps) continue; - //(*testout) << "lam3 <= eps" << endl; + if (fabs (lam3) > eps) continue; + //(*testout) << "lam3 <= eps" << endl; - double lam1 = (faces[i].w1 * v0); - double lam2 = (faces[i].w2 * v0); + double lam1 = (faces[i].w1 * v0); + double lam2 = (faces[i].w2 * v0); - if (lam1 >= -eps_base1 && lam2 >= -eps_base1 && lam1+lam2 <= 1+eps_base1) - { - point_on_faces.Append(i); + if (lam1 >= -eps_base1 && lam2 >= -eps_base1 && lam1+lam2 <= 1+eps_base1) + { + point_on_faces.Append(i); - double scal = vn * faces[i].nn; // n->nn + double scal = vn * faces[i].nn; // n->nn - res = DOES_INTERSECT; - if (scal > eps_base1) res = IS_OUTSIDE; - if (scal < -eps_base1) res = IS_INSIDE; - } - } + res = DOES_INTERSECT; + if (scal > eps_base1) res = IS_OUTSIDE; + if (scal < -eps_base1) res = IS_INSIDE; + } + } - //(*testout) << "point_on_faces.Size() " << point_on_faces.Size() - // << " res " << res << endl; + //(*testout) << "point_on_faces.Size() " << point_on_faces.Size() + // << " res " << res << endl; + + if (point_on_faces.Size() == 0) + return PointInSolid (p, 0); + if (point_on_faces.Size() == 1) + return res; + + + + + double mindist(0); + bool first = true; + + for(int i=0; i eps && (first || dist < mindist)) + { + mindist = dist; + first = false; + } + } + } + + Point<3> p2 = p + (1e-4*mindist) * vn; + res = PointInSolid (p2, eps); + + // (*testout) << "mindist " << mindist << " res " << res << endl; - if (point_on_faces.Size() == 0) - return PointInSolid (p, 0); - if (point_on_faces.Size() == 1) return res; + } - - double mindist(0); - bool first = true; - - for(int i=0; i eps && (first || dist < mindist)) - { - mindist = dist; - first = false; - } - } - } - - Point<3> p2 = p + (1e-4*mindist) * vn; - res = PointInSolid (p2, eps); - - // (*testout) << "mindist " << mindist << " res " << res << endl; - - return res; -} - -#else - - // check how many faces a ray starting in p+alpha*v intersects -INSOLID_TYPE Polyhedra :: VecInSolid (const Point<3> & p, - const Vec<3> & v, - double eps) const -{ - if (!poly_bbox.IsIn (p, eps)) - return IS_OUTSIDE; + INSOLID_TYPE Polyhedra :: VecInSolidNew (const Point<3> & p, + const Vec<3> & v, + double eps, bool printing) const + { + if (!poly_bbox.IsIn (p, eps)) + return IS_OUTSIDE; - // random (?) direction: - Vec<3> n(-0.424621, 0.1543, 0.89212238); + // random (?) direction: + Vec<3> n(-0.424621, 0.1543, 0.89212238); - int cnt = 0; - for (auto & face : faces) - { - Vec<3> v0 = p - points[face.pnums[0]]; + int cnt = 0; + for (auto & face : faces) + { + Vec<3> v0 = p - points[face.pnums[0]]; + if (printing) + { + *testout << "face: "; + for (int j = 0; j < 3; j++) + *testout << points[face.pnums[j]] << " "; + *testout << endl; + } + double lamn = face.nn * v0; - double lamn = face.nn * v0; + if (fabs(lamn) < eps) // point is in plane of face + { + double lam1 = face.w1 * v0; + double lam2 = face.w2 * v0; + double lam3 = 1-lam1-lam2; + if (printing) + *testout << "lam = " << lam1 << " " << lam2 << " " << lam3 << endl; + if (lam1 >= -eps_base1 && lam2 >= -eps_base1 && lam3 >= -eps_base1) + { // point is close to trianlge, perturbe by alpha*v + double dlamn = face.nn*v; - if (fabs(lamn) < eps) // point is in plance of face - { - double lam1 = face.w1 * v0; - double lam2 = face.w2 * v0; - double lam3 = 1-lam1-lam2; + if (fabs(dlamn) < 1e-8) // vec also in plane + { + if (printing) + *testout << "tang in plane" << endl; + double dlam1 = face.w1 * v; + double dlam2 = face.w2 * v; + double dlam3 = 1-dlam1-dlam2; + if (printing) + *testout << "dlam = " << dlam1 << " " << dlam2 << " " << dlam3 << endl; + bool in1 = lam1 > eps_base1 || dlam1 > -eps_base1; + bool in2 = lam2 > eps_base1 || dlam2 > -eps_base1; + bool in3 = lam3 > eps_base1 || dlam3 > -eps_base1; + if (in1 && in2 && in3) + return DOES_INTERSECT; + } + else // vec out of plane + { + if (printing) + *testout << "out of plane"; + double dlamn = -(face.n * v) / (face.n * n); + if (printing) + *testout << "dlamn = " << dlamn << endl; + if (dlamn < 0) continue; // ray goes not in direction of face - if (lam1 >= -eps_base1 && lam2 >= -eps_base1 && lam3 >= -eps_base1) - { // point is close to trianlge, perturbe by alpha*v - double dlamn = face.nn*v; - double dlam1 = face.w1 * v; - double dlam2 = face.w2 * v; - double dlam3 = 1-dlam1-dlam2; + Vec<3> drs = v + dlamn * n; + if (printing) + { + *testout << "drs = " << drs << endl; + *testout << "face.w1 = " << face.w1 << endl; + *testout << "face.w2 = " << face.w2 << endl; + } + + double dlam1 = face.w1 * drs; + double dlam2 = face.w2 * drs; + double dlam3 = -dlam1-dlam2; - if (fabs(dlamn) < 1e-8) // vec also in plane - { - bool in1 = lam1 > eps_base1 || dlam1 > -eps_base1; - bool in2 = lam2 > eps_base1 || dlam2 > -eps_base1; - bool in3 = lam3 > eps_base1 || dlam3 > -eps_base1; - if (in1 && in2 && in3) - return DOES_INTERSECT; - } - else // vec out of plane - { - double dlamn = -(face.n * v) / (face.n * n); - if (dlamn < 0) continue; // ray goes not in direction of face - - Vec<3> drs = v0 + lamn * n; + if (printing) + *testout << "dlam = " << dlam1 << " " << dlam2 << " " << dlam3 << endl; - double dlam1 = dlamn * face.w1 * v; - double dlam2 = dlamn * face.w2 * v; - double dlam3 = 1-dlam1-dlam2; - - bool in1 = lam1 > eps_base1 || dlam1 > -eps_base1; - bool in2 = lam2 > eps_base1 || dlam2 > -eps_base1; - bool in3 = lam3 > eps_base1 || dlam3 > -eps_base1; - - if (in1 && in2 && in3) - cnt++; - } - } - } - else - { - double lamn = -(face.n * v0) / (face.n * n); + bool in1 = lam1 > eps_base1 || dlam1 > -eps_base1; + bool in2 = lam2 > eps_base1 || dlam2 > -eps_base1; + bool in3 = lam3 > eps_base1 || dlam3 > -eps_base1; + + if (in1 && in2 && in3) + { + if (printing) + *testout << "hit" << endl; + cnt++; + } + } + } + } + else + { + double lamn = -(face.n * v0) / (face.n * n); - if (lamn < 0) continue; // ray goes not in direction of face + if (lamn < 0) continue; // ray goes not in direction of face - Vec<3> rs = v0 + lamn * n; + Vec<3> rs = v0 + lamn * n; - double lam1 = face.w1 * rs; - double lam2 = face.w2 * rs; - double lam3 = 1-lam1-lam2; - if (lam1 >= 0 && lam2 >= 0 && lam3 >= 0) - cnt++; - } - } + double lam1 = face.w1 * rs; + double lam2 = face.w2 * rs; + double lam3 = 1-lam1-lam2; + if (lam1 >= 0 && lam2 >= 0 && lam3 >= 0) + { + if (printing) + *testout << "hit" << endl; + cnt++; + } + } + } - return (cnt % 2) ? IS_INSIDE : IS_OUTSIDE; -} + return (cnt % 2) ? IS_INSIDE : IS_OUTSIDE; + } -#endif + + INSOLID_TYPE Polyhedra :: VecInSolid (const Point<3> & p, + const Vec<3> & v, + double eps) const + { + return VecInSolidOld (p, v, eps); + /* + auto oldval = VecInSolidOld (p, v, eps); + auto newval = VecInSolidNew (p, v, eps); + if (oldval != newval) + { + *testout << "different decision: oldval = " << oldval + << " newval = " << newval << endl; + *testout << "p = " << p << ", v = " << v << endl; + VecInSolidNew (p, v, eps, true); + *testout << "Poly:" << endl; + for (auto & face : faces) + { + for (int j = 0; j < 3; j++) + *testout << points[face.pnums[j]] << " "; + *testout << endl; + } + } + return newval; + */ + } @@ -330,28 +384,28 @@ INSOLID_TYPE Polyhedra :: VecInSolid (const Point<3> & p, -/* -INSOLID_TYPE Polyhedra :: VecInSolid2 (const Point<3> & p, - const Vec<3> & v1, - const Vec<3> & v2, - double eps) const -{ - INSOLID_TYPE res; + /* + INSOLID_TYPE Polyhedra :: VecInSolid2 (const Point<3> & p, + const Vec<3> & v1, + const Vec<3> & v2, + double eps) const + { + INSOLID_TYPE res; - res = VecInSolid(p,v1,eps); - if(res != DOES_INTERSECT) - return res; + res = VecInSolid(p,v1,eps); + if(res != DOES_INTERSECT) + return res; - int point_on_n_faces = 0; + int point_on_n_faces = 0; - Vec<3> v1n = v1; - v1n.Normalize(); - Vec<3> v2n = v2; - v2n.Normalize(); + Vec<3> v1n = v1; + v1n.Normalize(); + Vec<3> v2n = v2; + v2n.Normalize(); - for (int i = 0; i < faces.Size(); i++) - { + for (int i = 0; i < faces.Size(); i++) + { const Point<3> & p1 = points[faces[i].pnums[0]]; Vec<3> v0 = p - p1; @@ -363,146 +417,146 @@ INSOLID_TYPE Polyhedra :: VecInSolid2 (const Point<3> & p, double lam2 = (faces[i].w2 * v0); if (lam1 >= -eps && lam2 >= -eps && lam1+lam2 <= 1+eps) - { - double scal1 = v1n * faces[i].n; - if (fabs (scal1) > eps) continue; + { + double scal1 = v1n * faces[i].n; + if (fabs (scal1) > eps) continue; - point_on_n_faces++; + point_on_n_faces++; - double scal2 = v2n * faces[i].n; - res = DOES_INTERSECT; - if (scal2 > eps) res = IS_OUTSIDE; - if (scal2 < -eps) res = IS_INSIDE; - } - } + double scal2 = v2n * faces[i].n; + res = DOES_INTERSECT; + if (scal2 > eps) res = IS_OUTSIDE; + if (scal2 < -eps) res = IS_INSIDE; + } + } - if (point_on_n_faces == 1) - return res; + if (point_on_n_faces == 1) + return res; - cerr << "primitive::vecinsolid2 makes nonsense for polyhedra" << endl; + cerr << "primitive::vecinsolid2 makes nonsense for polyhedra" << endl; - return Primitive :: VecInSolid2 (p, v1, v2, eps); -} -*/ + return Primitive :: VecInSolid2 (p, v1, v2, eps); + } + */ -INSOLID_TYPE Polyhedra :: VecInSolid2 (const Point<3> & p, - const Vec<3> & v1, - const Vec<3> & v2, - double eps) const -{ - //(*testout) << "VecInSolid2 eps " << eps << endl; - INSOLID_TYPE res = VecInSolid(p,v1,eps); - //(*testout) << "VecInSolid = " < & p, + const Vec<3> & v1, + const Vec<3> & v2, + double eps) const + { + //(*testout) << "VecInSolid2 eps " << eps << endl; + INSOLID_TYPE res = VecInSolid(p,v1,eps); + //(*testout) << "VecInSolid = " < v1n = v1; - v1n.Normalize(); - Vec<3> v2n = v2 - (v2 * v1n) * v1n; - v2n.Normalize(); + Vec<3> v1n = v1; + v1n.Normalize(); + Vec<3> v2n = v2 - (v2 * v1n) * v1n; + v2n.Normalize(); - double cosv2, cosv2max = -99; + double cosv2, cosv2max = -99; - for (int i = 0; i < faces.Size(); i++) - { - const Point<3> & p1 = points[faces[i].pnums[0]]; + for (int i = 0; i < faces.Size(); i++) + { + const Point<3> & p1 = points[faces[i].pnums[0]]; - Vec<3> v0 = p - p1; - if (fabs (faces[i].nn * v0) > eps) continue; // n->nn - if (fabs (v1n * faces[i].nn) > eps_base1) continue; // n->nn + Vec<3> v0 = p - p1; + if (fabs (faces[i].nn * v0) > eps) continue; // n->nn + if (fabs (v1n * faces[i].nn) > eps_base1) continue; // n->nn - double lam1 = (faces[i].w1 * v0); - double lam2 = (faces[i].w2 * v0); + double lam1 = (faces[i].w1 * v0); + double lam2 = (faces[i].w2 * v0); - if (lam1 >= -eps_base1 && lam2 >= -eps_base1 && lam1+lam2 <= 1+eps_base1) - { - // v1 is in face + if (lam1 >= -eps_base1 && lam2 >= -eps_base1 && lam1+lam2 <= 1+eps_base1) + { + // v1 is in face - Point<3> fc = Center (points[faces[i].pnums[0]], - points[faces[i].pnums[1]], - points[faces[i].pnums[2]]); + Point<3> fc = Center (points[faces[i].pnums[0]], + points[faces[i].pnums[1]], + points[faces[i].pnums[2]]); - Vec<3> vpfc = fc - p; - cosv2 = (v2n * vpfc) / vpfc.Length(); - if (cosv2 > cosv2max) - { - cosv2max = cosv2; - point_on_n_faces++; + Vec<3> vpfc = fc - p; + cosv2 = (v2n * vpfc) / vpfc.Length(); + if (cosv2 > cosv2max) + { + cosv2max = cosv2; + point_on_n_faces++; - double scal2 = v2n * faces[i].nn; // n->nn - res = DOES_INTERSECT; - if (scal2 > eps_base1) res = IS_OUTSIDE; - if (scal2 < -eps_base1) res = IS_INSIDE; + double scal2 = v2n * faces[i].nn; // n->nn + res = DOES_INTERSECT; + if (scal2 > eps_base1) res = IS_OUTSIDE; + if (scal2 < -eps_base1) res = IS_INSIDE; - } - } + } + } + } + + if (point_on_n_faces >= 1) + return res; + + (*testout) << "primitive::vecinsolid2 makes nonsense for polyhedra" << endl; + cerr << "primitive::vecinsolid2 makes nonsense for polyhedra" << endl; + + return Primitive :: VecInSolid2 (p, v1, v2, eps); } - if (point_on_n_faces >= 1) - return res; - - (*testout) << "primitive::vecinsolid2 makes nonsense for polyhedra" << endl; - cerr << "primitive::vecinsolid2 makes nonsense for polyhedra" << endl; - - return Primitive :: VecInSolid2 (p, v1, v2, eps); -} - -void Polyhedra :: GetTangentialVecSurfaceIndices2 (const Point<3> & p, const Vec<3> & v1, const Vec<3> & v2, - NgArray & surfind, double eps) const -{ - Vec<3> v1n = v1; - v1n.Normalize(); - Vec<3> v2n = v2; // - (v2 * v1n) * v1n; - v2n.Normalize(); + void Polyhedra :: GetTangentialVecSurfaceIndices2 (const Point<3> & p, const Vec<3> & v1, const Vec<3> & v2, + NgArray & surfind, double eps) const + { + Vec<3> v1n = v1; + v1n.Normalize(); + Vec<3> v2n = v2; // - (v2 * v1n) * v1n; + v2n.Normalize(); - for (int i = 0; i < faces.Size(); i++) - { - const Point<3> & p1 = points[faces[i].pnums[0]]; + for (int i = 0; i < faces.Size(); i++) + { + const Point<3> & p1 = points[faces[i].pnums[0]]; - Vec<3> v0 = p - p1; - if (fabs (v0 * faces[i].nn) > eps) continue; // n->nn - if (fabs (v1n * faces[i].nn) > eps_base1) continue; // n->nn - if (fabs (v2n * faces[i].nn) > eps_base1) continue; // n->nn + Vec<3> v0 = p - p1; + if (fabs (v0 * faces[i].nn) > eps) continue; // n->nn + if (fabs (v1n * faces[i].nn) > eps_base1) continue; // n->nn + if (fabs (v2n * faces[i].nn) > eps_base1) continue; // n->nn - double lam01 = (faces[i].w1 * v0); - double lam02 = (faces[i].w2 * v0); - double lam03 = 1-lam01-lam02; - double lam11 = (faces[i].w1 * v1); - double lam12 = (faces[i].w2 * v1); - double lam13 = -lam11-lam12; - double lam21 = (faces[i].w1 * v2); - double lam22 = (faces[i].w2 * v2); - double lam23 = -lam21-lam22; + double lam01 = (faces[i].w1 * v0); + double lam02 = (faces[i].w2 * v0); + double lam03 = 1-lam01-lam02; + double lam11 = (faces[i].w1 * v1); + double lam12 = (faces[i].w2 * v1); + double lam13 = -lam11-lam12; + double lam21 = (faces[i].w1 * v2); + double lam22 = (faces[i].w2 * v2); + double lam23 = -lam21-lam22; - bool ok1 = lam01 > eps_base1 || - (lam01 > -eps_base1 && lam11 > eps_base1) || - (lam01 > -eps_base1 && lam11 > -eps_base1 && lam21 > eps_base1); + bool ok1 = lam01 > eps_base1 || + (lam01 > -eps_base1 && lam11 > eps_base1) || + (lam01 > -eps_base1 && lam11 > -eps_base1 && lam21 > eps_base1); - bool ok2 = lam02 > eps_base1 || - (lam02 > -eps_base1 && lam12 > eps_base1) || - (lam02 > -eps_base1 && lam12 > -eps_base1 && lam22 > eps_base1); + bool ok2 = lam02 > eps_base1 || + (lam02 > -eps_base1 && lam12 > eps_base1) || + (lam02 > -eps_base1 && lam12 > -eps_base1 && lam22 > eps_base1); - bool ok3 = lam03 > eps_base1 || - (lam03 > -eps_base1 && lam13 > eps_base1) || - (lam03 > -eps_base1 && lam13 > -eps_base1 && lam23 > eps_base1); + bool ok3 = lam03 > eps_base1 || + (lam03 > -eps_base1 && lam13 > eps_base1) || + (lam03 > -eps_base1 && lam13 > -eps_base1 && lam23 > eps_base1); - if (ok1 && ok2 && ok3) - { - if (!surfind.Contains (GetSurfaceId(faces[i].planenr))) - surfind.Append (GetSurfaceId(faces[i].planenr)); - } - } -} + if (ok1 && ok2 && ok3) + { + if (!surfind.Contains (GetSurfaceId(faces[i].planenr))) + surfind.Append (GetSurfaceId(faces[i].planenr)); + } + } + } @@ -515,101 +569,101 @@ void Polyhedra :: GetTangentialVecSurfaceIndices2 (const Point<3> & p, const Vec -void Polyhedra :: GetPrimitiveData (const char *& classname, - NgArray & coeffs) const -{ - classname = "Polyhedra"; - coeffs.SetSize(0); - coeffs.Append (points.Size()); - coeffs.Append (faces.Size()); - coeffs.Append (planes.Size()); + void Polyhedra :: GetPrimitiveData (const char *& classname, + NgArray & coeffs) const + { + classname = "Polyhedra"; + coeffs.SetSize(0); + coeffs.Append (points.Size()); + coeffs.Append (faces.Size()); + coeffs.Append (planes.Size()); - /* - int i, j; - for (i = 1; i <= planes.Size(); i++) - { + /* + int i, j; + for (i = 1; i <= planes.Size(); i++) + { planes.Elem(i)->Print (*testout); - } - for (i = 1; i <= faces.Size(); i++) - { + } + for (i = 1; i <= faces.Size(); i++) + { (*testout) << "face " << i << " has plane " << faces.Get(i).planenr << endl; for (j = 1; j <= 3; j++) - (*testout) << points.Get(faces.Get(i).pnums[j-1]); + (*testout) << points.Get(faces.Get(i).pnums[j-1]); (*testout) << endl; - } - */ -} + } + */ + } -void Polyhedra :: SetPrimitiveData (NgArray & /* coeffs */) -{ - ; -} + void Polyhedra :: SetPrimitiveData (NgArray & /* coeffs */) + { + ; + } -void Polyhedra :: Reduce (const BoxSphere<3> & box) -{ - for (int i = 0; i < planes.Size(); i++) - surfaceactive[i] = 0; + void Polyhedra :: Reduce (const BoxSphere<3> & box) + { + for (int i = 0; i < planes.Size(); i++) + surfaceactive[i] = 0; - for (int i = 0; i < faces.Size(); i++) - if (FaceBoxIntersection (i, box)) - surfaceactive[faces[i].planenr] = 1; -} + for (int i = 0; i < faces.Size(); i++) + if (FaceBoxIntersection (i, box)) + surfaceactive[faces[i].planenr] = 1; + } -void Polyhedra :: UnReduce () -{ - for (int i = 0; i < planes.Size(); i++) - surfaceactive[i] = 1; -} + void Polyhedra :: UnReduce () + { + for (int i = 0; i < planes.Size(); i++) + surfaceactive[i] = 1; + } -int Polyhedra :: AddPoint (const Point<3> & p) -{ - if(points.Size() == 0) - poly_bbox.Set(p); - else - poly_bbox.Add(p); + int Polyhedra :: AddPoint (const Point<3> & p) + { + if(points.Size() == 0) + poly_bbox.Set(p); + else + poly_bbox.Add(p); - points.Append (p); - return points.Size(); -} + points.Append (p); + return points.Size(); + } -int Polyhedra :: AddFace (int pi1, int pi2, int pi3, int inputnum) -{ - (*testout) << "polyhedra, add face " << pi1 << ", " << pi2 << ", " << pi3 << endl; + int Polyhedra :: AddFace (int pi1, int pi2, int pi3, int inputnum) + { + (*testout) << "polyhedra, add face " << pi1 << ", " << pi2 << ", " << pi3 << endl; - if(pi1 == pi2 || pi2 == pi3 || pi3 == pi1) - { - ostringstream msg; - msg << "Illegal point numbers for polyhedron face: " << pi1+1 << ", " << pi2+1 << ", " << pi3+1; - throw NgException(msg.str()); - } + if(pi1 == pi2 || pi2 == pi3 || pi3 == pi1) + { + ostringstream msg; + msg << "Illegal point numbers for polyhedron face: " << pi1+1 << ", " << pi2+1 << ", " << pi3+1; + throw NgException(msg.str()); + } - faces.Append (Face (pi1, pi2, pi3, points, inputnum)); + faces.Append (Face (pi1, pi2, pi3, points, inputnum)); - Point<3> p1 = points[pi1]; - Point<3> p2 = points[pi2]; - Point<3> p3 = points[pi3]; + Point<3> p1 = points[pi1]; + Point<3> p2 = points[pi2]; + Point<3> p3 = points[pi3]; - Vec<3> v1 = p2 - p1; - Vec<3> v2 = p3 - p1; + Vec<3> v1 = p2 - p1; + Vec<3> v2 = p3 - p1; - Vec<3> n = Cross (v1, v2); - n.Normalize(); + Vec<3> n = Cross (v1, v2); + n.Normalize(); - Plane pl (p1, n); -// int inverse; -// int identicto = -1; -// for (int i = 0; i < planes.Size(); i++) -// if (pl.IsIdentic (*planes[i], inverse, 1e-9*max3(v1.Length(),v2.Length(),Dist(p2,p3)))) -// { -// if (!inverse) -// identicto = i; -// } -// // cout << "is identic = " << identicto << endl; -// identicto = -1; // changed April 10, JS + Plane pl (p1, n); + // int inverse; + // int identicto = -1; + // for (int i = 0; i < planes.Size(); i++) + // if (pl.IsIdentic (*planes[i], inverse, 1e-9*max3(v1.Length(),v2.Length(),Dist(p2,p3)))) + // { + // if (!inverse) + // identicto = i; + // } + // // cout << "is identic = " << identicto << endl; + // identicto = -1; // changed April 10, JS -// if (identicto != -1) -// faces.Last().planenr = identicto; -// else + // if (identicto != -1) + // faces.Last().planenr = identicto; + // else { planes.Append (new Plane (p1, n)); surfaceactive.Append (1); @@ -617,190 +671,190 @@ int Polyhedra :: AddFace (int pi1, int pi2, int pi3, int inputnum) faces.Last().planenr = planes.Size()-1; } -// (*testout) << "is plane nr " << faces.Last().planenr << endl; + // (*testout) << "is plane nr " << faces.Last().planenr << endl; - return faces.Size(); -} + return faces.Size(); + } -int Polyhedra :: FaceBoxIntersection (int fnr, const BoxSphere<3> & box) const -{ - /* - (*testout) << "check face box intersection, fnr = " << fnr << endl; - (*testout) << "box = " << box << endl; - (*testout) << "face-box = " << faces[fnr].bbox << endl; - */ + int Polyhedra :: FaceBoxIntersection (int fnr, const BoxSphere<3> & box) const + { + /* + (*testout) << "check face box intersection, fnr = " << fnr << endl; + (*testout) << "box = " << box << endl; + (*testout) << "face-box = " << faces[fnr].bbox << endl; + */ - if (!faces[fnr].bbox.Intersect (box)) - return 0; + if (!faces[fnr].bbox.Intersect (box)) + return 0; - const Point<3> & p1 = points[faces[fnr].pnums[0]]; - const Point<3> & p2 = points[faces[fnr].pnums[1]]; - const Point<3> & p3 = points[faces[fnr].pnums[2]]; + const Point<3> & p1 = points[faces[fnr].pnums[0]]; + const Point<3> & p2 = points[faces[fnr].pnums[1]]; + const Point<3> & p3 = points[faces[fnr].pnums[2]]; - double dist2 = MinDistTP2 (p1, p2, p3, box.Center()); - /* - (*testout) << "p1 = " << p1 << endl; - (*testout) << "p2 = " << p2 << endl; - (*testout) << "p3 = " << p3 << endl; + double dist2 = MinDistTP2 (p1, p2, p3, box.Center()); + /* + (*testout) << "p1 = " << p1 << endl; + (*testout) << "p2 = " << p2 << endl; + (*testout) << "p3 = " << p3 << endl; - (*testout) << "box.Center() = " << box.Center() << endl; - (*testout) << "center = " << box.Center() << endl; - (*testout) << "dist2 = " << dist2 << endl; - (*testout) << "diam = " << box.Diam() << endl; - */ - if (dist2 < sqr (box.Diam()/2)) - { - // (*testout) << "intersect" << endl; - return 1; - } - return 0; -} - - -void Polyhedra :: GetPolySurfs(NgArray < NgArray * > & polysurfs) -{ - int maxnum = -1; - - for(int i = 0; i maxnum) - maxnum = faces[i].inputnr; - } - - polysurfs.SetSize(maxnum+1); - for(int i=0; i; - - for(int i = 0; iAppend(faces[i].planenr); -} - - -void Polyhedra::CalcSpecialPoints (NgArray > & pts) const -{ - for (int i = 0; i < points.Size(); i++) - pts.Append (points[i]); -} - - -void Polyhedra :: AnalyzeSpecialPoint (const Point<3> & /* pt */, - NgArray > & /* specpts */) const -{ - ; -} - -Vec<3> Polyhedra :: SpecialPointTangentialVector (const Point<3> & p, int s1, int s2) const -{ - const double eps = 1e-10*poly_bbox.Diam(); - - for (int fi1 = 0; fi1 < faces.Size(); fi1++) - for (int fi2 = 0; fi2 < faces.Size(); fi2++) + (*testout) << "box.Center() = " << box.Center() << endl; + (*testout) << "center = " << box.Center() << endl; + (*testout) << "dist2 = " << dist2 << endl; + (*testout) << "diam = " << box.Diam() << endl; + */ + if (dist2 < sqr (box.Diam()/2)) { - int si1 = faces[fi1].planenr; - int si2 = faces[fi2].planenr; + // (*testout) << "intersect" << endl; + return 1; + } + return 0; + } - if (surfaceids[si1] != s1 || surfaceids[si2] != s2) continue; - //(*testout) << "check pair fi1/fi2 " << fi1 << "/" << fi2 << endl; + void Polyhedra :: GetPolySurfs(NgArray < NgArray * > & polysurfs) + { + int maxnum = -1; + + for(int i = 0; i maxnum) + maxnum = faces[i].inputnr; + } + + polysurfs.SetSize(maxnum+1); + for(int i=0; i; + + for(int i = 0; iAppend(faces[i].planenr); + } + + + void Polyhedra::CalcSpecialPoints (NgArray > & pts) const + { + for (int i = 0; i < points.Size(); i++) + pts.Append (points[i]); + } + + + void Polyhedra :: AnalyzeSpecialPoint (const Point<3> & /* pt */, + NgArray > & /* specpts */) const + { + ; + } + + Vec<3> Polyhedra :: SpecialPointTangentialVector (const Point<3> & p, int s1, int s2) const + { + const double eps = 1e-10*poly_bbox.Diam(); + + for (int fi1 = 0; fi1 < faces.Size(); fi1++) + for (int fi2 = 0; fi2 < faces.Size(); fi2++) + { + int si1 = faces[fi1].planenr; + int si2 = faces[fi2].planenr; + + if (surfaceids[si1] != s1 || surfaceids[si2] != s2) continue; + + //(*testout) << "check pair fi1/fi2 " << fi1 << "/" << fi2 << endl; - Vec<3> n1 = GetSurface(si1) . GetNormalVector (p); - Vec<3> n2 = GetSurface(si2) . GetNormalVector (p); - Vec<3> t = Cross (n1, n2); + Vec<3> n1 = GetSurface(si1) . GetNormalVector (p); + Vec<3> n2 = GetSurface(si2) . GetNormalVector (p); + Vec<3> t = Cross (n1, n2); - //(*testout) << "t = " << t << endl; + //(*testout) << "t = " << t << endl; - /* - int samepts = 0; - for (int j = 0; j < 3; j++) - for (int k = 0; k < 3; k++) + /* + int samepts = 0; + for (int j = 0; j < 3; j++) + for (int k = 0; k < 3; k++) if (Dist(points[faces[fi1].pnums[j]], - points[faces[fi2].pnums[k]]) < eps) - samepts++; - if (samepts < 2) continue; - */ + points[faces[fi2].pnums[k]]) < eps) + samepts++; + if (samepts < 2) continue; + */ - bool shareedge = false; - for(int j = 0; !shareedge && j < 3; j++) - { - Vec<3> v1 = points[faces[fi1].pnums[(j+1)%3]] - points[faces[fi1].pnums[j]]; - double smax = v1.Length(); - v1 *= 1./smax; + bool shareedge = false; + for(int j = 0; !shareedge && j < 3; j++) + { + Vec<3> v1 = points[faces[fi1].pnums[(j+1)%3]] - points[faces[fi1].pnums[j]]; + double smax = v1.Length(); + v1 *= 1./smax; - int pospos; - if(fabs(v1(0)) > 0.5) - pospos = 0; - else if(fabs(v1(1)) > 0.5) - pospos = 1; - else - pospos = 2; + int pospos; + if(fabs(v1(0)) > 0.5) + pospos = 0; + else if(fabs(v1(1)) > 0.5) + pospos = 1; + else + pospos = 2; - double sp = (p(pospos) - points[faces[fi1].pnums[j]](pospos)) / v1(pospos); - if(sp < -eps || sp > smax+eps) - continue; + double sp = (p(pospos) - points[faces[fi1].pnums[j]](pospos)) / v1(pospos); + if(sp < -eps || sp > smax+eps) + continue; - for (int k = 0; !shareedge && k < 3; k ++) - { - Vec<3> v2 = points[faces[fi2].pnums[(k+1)%3]] - points[faces[fi2].pnums[k]]; - v2.Normalize(); - if(v2 * v1 > 0) - v2 -= v1; - else - v2 += v1; + for (int k = 0; !shareedge && k < 3; k ++) + { + Vec<3> v2 = points[faces[fi2].pnums[(k+1)%3]] - points[faces[fi2].pnums[k]]; + v2.Normalize(); + if(v2 * v1 > 0) + v2 -= v1; + else + v2 += v1; - //(*testout) << "v2.Length2() " << v2.Length2() << endl; + //(*testout) << "v2.Length2() " << v2.Length2() << endl; - if(v2.Length2() > 1e-18) - continue; + if(v2.Length2() > 1e-18) + continue; - double sa,sb; + double sa,sb; - sa = (points[faces[fi2].pnums[k]](pospos) - points[faces[fi1].pnums[j]](pospos)) / v1(pospos); - sb = (points[faces[fi2].pnums[(k+1)%3]](pospos) - points[faces[fi1].pnums[j]](pospos)) / v1(pospos); + sa = (points[faces[fi2].pnums[k]](pospos) - points[faces[fi1].pnums[j]](pospos)) / v1(pospos); + sb = (points[faces[fi2].pnums[(k+1)%3]](pospos) - points[faces[fi1].pnums[j]](pospos)) / v1(pospos); - if(Dist(points[faces[fi1].pnums[j]] + sa*v1, points[faces[fi2].pnums[k]]) > eps) - continue; + if(Dist(points[faces[fi1].pnums[j]] + sa*v1, points[faces[fi2].pnums[k]]) > eps) + continue; - if(sa > sb) - { - double aux = sa; sa = sb; sb = aux; - } + if(sa > sb) + { + double aux = sa; sa = sb; sb = aux; + } - //testout->precision(20); - //(*testout) << "sa " << sa << " sb " << sb << " smax " << smax << " sp " << sp << " v1 " << v1 << endl; - //testout->precision(8); + //testout->precision(20); + //(*testout) << "sa " << sa << " sb " << sb << " smax " << smax << " sp " << sp << " v1 " << v1 << endl; + //testout->precision(8); - shareedge = (sa < -eps && sb > eps) || - (sa < smax-eps && sb > smax+eps) || - (sa > -eps && sb < smax+eps); + shareedge = (sa < -eps && sb > eps) || + (sa < smax-eps && sb > smax+eps) || + (sa > -eps && sb < smax+eps); - if(!shareedge) - continue; + if(!shareedge) + continue; - sa = max2(sa,0.); - sb = min2(sb,smax); + sa = max2(sa,0.); + sb = min2(sb,smax); - if(sp < sa+eps) - shareedge = (t * v1 > 0); - else if (sp > sb-eps) - shareedge = (t * v1 < 0); + if(sp < sa+eps) + shareedge = (t * v1 > 0); + else if (sp > sb-eps) + shareedge = (t * v1 < 0); - } - } - if (!shareedge) continue; + } + } + if (!shareedge) continue; - t.Normalize(); + t.Normalize(); - return t; - } + return t; + } - return Vec<3> (0,0,0); -} + return Vec<3> (0,0,0); + } } diff --git a/libsrc/csg/polyhedra.hpp b/libsrc/csg/polyhedra.hpp index f7a14cd4..720786e4 100644 --- a/libsrc/csg/polyhedra.hpp +++ b/libsrc/csg/polyhedra.hpp @@ -54,10 +54,18 @@ namespace netgen virtual INSOLID_TYPE BoxInSolid (const BoxSphere<3> & box) const; virtual INSOLID_TYPE PointInSolid (const Point<3> & p, double eps) const; + virtual INSOLID_TYPE VecInSolidNew (const Point<3> & p, + const Vec<3> & v, + double eps, bool printing = false) const; + virtual INSOLID_TYPE VecInSolidOld (const Point<3> & p, + const Vec<3> & v, + double eps) const; virtual INSOLID_TYPE VecInSolid (const Point<3> & p, const Vec<3> & v, double eps) const; + + // checks if lim s->0 lim t->0 p + t(v1 + s v2) in solid virtual INSOLID_TYPE VecInSolid2 (const Point<3> & p, const Vec<3> & v1, From 4d2e4fea4463cd5abb058fa96531aa8230410ed4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20Sch=C3=B6berl?= Date: Fri, 16 Oct 2020 09:44:11 +0200 Subject: [PATCH 197/384] unique-ptr for TangentialSolid --- libsrc/csg/edgeflw.cpp | 20 ++++++++++++-------- libsrc/csg/singularref.cpp | 6 +++--- libsrc/csg/solid.cpp | 4 +++- libsrc/csg/solid.hpp | 2 +- libsrc/csg/specpoin.cpp | 36 ++++++++++++++++++------------------ 5 files changed, 37 insertions(+), 31 deletions(-) diff --git a/libsrc/csg/edgeflw.cpp b/libsrc/csg/edgeflw.cpp index 106a951c..850c28ad 100644 --- a/libsrc/csg/edgeflw.cpp +++ b/libsrc/csg/edgeflw.cpp @@ -970,7 +970,7 @@ namespace netgen for (int i = 0; i < geometry.GetNTopLevelObjects(); i++) { - Solid * locsol; + // Solid * locsol; if (geometry.GetTopLevelObject(i)->GetLayer() != layer) continue; @@ -978,7 +978,8 @@ namespace netgen const Solid * sol = geometry.GetTopLevelObject(i)->GetSolid(); const Surface * surf = geometry.GetTopLevelObject(i)->GetSurface(); - sol -> TangentialSolid (hp, locsol, locsurfind, size*ideps); + // sol -> TangentialSolid (hp, locsol, locsurfind, size*ideps); + auto locsol = sol -> TangentialSolid (hp, locsurfind, size*ideps); //*testout << "hp = " << hp << endl; //(*testout) << "locsol: " << endl; @@ -995,7 +996,8 @@ namespace netgen ReducePrimitiveIterator rpi(boxp); UnReducePrimitiveIterator urpi; - ((Solid*)locsol) -> IterateSolid (rpi); + // ((Solid*)locsol) -> IterateSolid (rpi); + locsol -> IterateSolid (rpi); locsol -> CalcSurfaceInverse (); @@ -1020,7 +1022,8 @@ namespace netgen } } - ((Solid*)locsol) -> IterateSolid (urpi); + // ((Solid*)locsol) -> IterateSolid (urpi); + locsol -> IterateSolid (urpi); if (debug) @@ -1259,7 +1262,7 @@ namespace netgen m *= -1; } } - delete locsol; + // delete locsol; } @@ -1780,7 +1783,7 @@ namespace netgen int nsurf = geometry.GetNSurf(); int layer = 0; - Solid * tansol; + // Solid * tansol; NgArray tansurfind; double size = geometry.MaxSize(); @@ -1838,7 +1841,8 @@ namespace netgen continue; const Solid * sol = geometry.GetTopLevelObject(j)->GetSolid(); - sol -> TangentialSolid (p1, tansol, tansurfind, ideps*size); + // sol -> TangentialSolid (p1, tansol, tansurfind, ideps*size); + auto tansol = sol -> TangentialSolid (p1, tansurfind, ideps*size); layer = geometry.GetTopLevelObject(j)->GetLayer(); @@ -1868,7 +1872,7 @@ namespace netgen // seg.invs1 = surfaces[i] -> Inverse(); // seg.invs2 = ! (surfaces[i] -> Inverse()); } - delete tansol; + // delete tansol; } } diff --git a/libsrc/csg/singularref.cpp b/libsrc/csg/singularref.cpp index a230c518..8dc1b7e5 100644 --- a/libsrc/csg/singularref.cpp +++ b/libsrc/csg/singularref.cpp @@ -168,7 +168,7 @@ void SingularPoint :: FindPoints (class Mesh & mesh) for (int k = 1; k <= 3; k++) { const Solid * solk(NULL); - Solid *tansol; + // Solid *tansol; switch (k) { case 1: solk = sol1; break; @@ -176,7 +176,7 @@ void SingularPoint :: FindPoints (class Mesh & mesh) case 3: solk = sol3; break; } - solk -> TangentialSolid (p, tansol, surfk, 1e-3); + auto tansol = solk -> TangentialSolid (p, surfk, 1e-3); (*testout) << "Tansol = " << *tansol << endl; if (!tansol) continue; @@ -195,7 +195,7 @@ void SingularPoint :: FindPoints (class Mesh & mesh) if (!surf.Contains (surfk[i])) surf.Append (surfk[i]); - delete tansol; + // delete tansol; } if (surf.Size() < 3) continue; diff --git a/libsrc/csg/solid.cpp b/libsrc/csg/solid.cpp index 6ba50cf7..b14dc1fe 100644 --- a/libsrc/csg/solid.cpp +++ b/libsrc/csg/solid.cpp @@ -638,13 +638,15 @@ namespace netgen } - void Solid :: TangentialSolid (const Point<3> & p, Solid *& tansol, NgArray & surfids, double eps) const + unique_ptr Solid :: TangentialSolid (const Point<3> & p, NgArray & surfids, double eps) const { int in, strin; + Solid * tansol = nullptr; RecTangentialSolid (p, tansol, surfids, in, strin, eps); surfids.SetSize (0); if (tansol) tansol -> GetTangentialSurfaceIndices (p, surfids, eps); + return unique_ptr (tansol); } diff --git a/libsrc/csg/solid.hpp b/libsrc/csg/solid.hpp index 51720275..3e884048 100644 --- a/libsrc/csg/solid.hpp +++ b/libsrc/csg/solid.hpp @@ -114,7 +114,7 @@ namespace netgen /// compute localization in point p - void TangentialSolid (const Point<3> & p, Solid *& tansol, NgArray & surfids, double eps) const; + unique_ptr TangentialSolid (const Point<3> & p, NgArray & surfids, double eps) const; /// compute localization in point p tangential to vector t void TangentialSolid2 (const Point<3> & p, const Vec<3> & t, diff --git a/libsrc/csg/specpoin.cpp b/libsrc/csg/specpoin.cpp index 16024e95..d4535e33 100644 --- a/libsrc/csg/specpoin.cpp +++ b/libsrc/csg/specpoin.cpp @@ -289,8 +289,8 @@ namespace netgen for (int j = 0; j < pts.Size(); j++) if (Dist (pts[j], box.Center()) < box.Diam()/2) { - Solid * tansol; - sol -> TangentialSolid (pts[j], tansol, surfids, 1e-9*size); + // Solid * tansol; + auto tansol = sol -> TangentialSolid (pts[j], surfids, 1e-9*size); if(!tansol) continue; @@ -314,7 +314,7 @@ namespace netgen if (AddPoint (pts[j], layer)) (*testout) << "cross point found, 1: " << pts[j] << endl; } - delete tansol; + // delete tansol; } } @@ -333,8 +333,8 @@ namespace netgen for (int j = 0; j < pts.Size(); j++) if (Dist (pts[j], box.Center()) < box.Diam()/2) { - Solid * tansol; - sol -> TangentialSolid (pts[j], tansol, surfids, 1e-9*size); + // Solid * tansol; + auto tansol = sol -> TangentialSolid (pts[j], surfids, 1e-9*size); if(!tansol) continue; @@ -358,7 +358,7 @@ namespace netgen if (AddPoint (pts[j], layer)) (*testout) << "cross point found, 2: " << pts[j] << endl; } - delete tansol; + // delete tansol; } } @@ -372,15 +372,15 @@ namespace netgen for (int j = 0; j < pts.Size(); j++) if (Dist (pts[j], box.Center()) < box.Diam()/2) { - Solid * tansol; - sol -> TangentialSolid (pts[j], tansol, surfids, 1e-9*size); + // Solid * tansol; + auto tansol = sol -> TangentialSolid (pts[j], surfids, 1e-9*size); if (tansol) // sol -> IsIn (pts[j], 1e-6*size) && !sol->IsStrictIn (pts[j], 1e-6*size) ) { if (AddPoint (pts[j], layer)) (*testout) << "extremal point found, 1: " << pts[j] << endl; } - delete tansol; + // delete tansol; } } } @@ -409,8 +409,8 @@ namespace netgen for (int j = 0; j < pts.Size(); j++) if (Dist (pts[j], box.Center()) < box.Diam()/2) { - Solid * tansol; - sol -> TangentialSolid (pts[j], tansol, surfids, 1e-9*size); + // Solid * tansol; + auto tansol = sol -> TangentialSolid (pts[j], surfids, 1e-9*size); if(!tansol) continue; @@ -434,7 +434,7 @@ namespace netgen if (AddPoint (pts[j], layer)) (*testout) << "cross point found, 1: " << pts[j] << endl; } - delete tansol; + // delete tansol; } } @@ -449,15 +449,15 @@ namespace netgen for (int j = 0; j < pts.Size(); j++) if (Dist (pts[j], box.Center()) < box.Diam()/2) { - Solid * tansol; - sol -> TangentialSolid (pts[j], tansol, surfids, 1e-9*size); + // Solid * tansol; + auto tansol = sol -> TangentialSolid (pts[j], surfids, 1e-9*size); if (tansol) // sol -> IsIn (pts[j], 1e-6*size) && !sol->IsStrictIn (pts[j], 1e-6*size) ) { if (AddPoint (pts[j], layer)) (*testout) << "extremal point found, spheres: " << pts[j] << endl; } - delete tansol; + // delete tansol; } } @@ -1829,8 +1829,8 @@ namespace netgen continue; - Solid * locsol; - sol -> TangentialSolid (p, locsol, surfind, ideps*geomsize); + // Solid * locsol; + auto locsol = sol -> TangentialSolid (p, surfind, ideps*geomsize); rep_surfind.SetSize (surfind.Size()); @@ -2158,7 +2158,7 @@ namespace netgen } - delete locsol; + // delete locsol; } } From b841b1c57b944d60891a71da342d0e949cf620de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20Sch=C3=B6berl?= Date: Fri, 16 Oct 2020 10:14:50 +0200 Subject: [PATCH 198/384] using bool for in/strict-in, and more unique-ptrs --- libsrc/csg/edgeflw.cpp | 6 +- libsrc/csg/solid.cpp | 138 ++++++++++++++++++++++------------------ libsrc/csg/solid.hpp | 24 +++---- libsrc/csg/specpoin.cpp | 16 ++--- 4 files changed, 98 insertions(+), 86 deletions(-) diff --git a/libsrc/csg/edgeflw.cpp b/libsrc/csg/edgeflw.cpp index 850c28ad..6746ecf8 100644 --- a/libsrc/csg/edgeflw.cpp +++ b/libsrc/csg/edgeflw.cpp @@ -1163,10 +1163,10 @@ namespace netgen m2 = fac * grad; // (*testout) << "hp = " << hp << ", m = " << m << ", m2 = " << m2 << endl; - Solid * locsol2; - locsol -> TangentialSolid3 (hp, m, m2, locsol2, locsurfind2, ideps*size); + // Solid * locsol2; + auto locsol2 = locsol -> TangentialSolid3 (hp, m, m2, locsurfind2, ideps*size); if (!locsol2) ok = 0; - delete locsol2; + // delete locsol2; if (ok) diff --git a/libsrc/csg/solid.cpp b/libsrc/csg/solid.cpp index b14dc1fe..58ed069e 100644 --- a/libsrc/csg/solid.cpp +++ b/libsrc/csg/solid.cpp @@ -640,7 +640,7 @@ namespace netgen unique_ptr Solid :: TangentialSolid (const Point<3> & p, NgArray & surfids, double eps) const { - int in, strin; + bool in, strin; Solid * tansol = nullptr; RecTangentialSolid (p, tansol, surfids, in, strin, eps); surfids.SetSize (0); @@ -651,7 +651,7 @@ namespace netgen void Solid :: RecTangentialSolid (const Point<3> & p, Solid *& tansol, NgArray & surfids, - int & in, int & strin, double eps) const + bool & in, bool & strin, double eps) const { tansol = NULL; @@ -673,7 +673,7 @@ namespace netgen } case SECTION: { - int in1, in2, strin1, strin2; + bool in1, in2, strin1, strin2; Solid * tansol1, * tansol2; s1 -> RecTangentialSolid (p, tansol1, surfids, in1, strin1, eps); @@ -688,13 +688,13 @@ namespace netgen else if (tansol2) tansol = tansol2; } - in = (in1 && in2); - strin = (strin1 && strin2); + in = in1 && in2; + strin = strin1 && strin2; break; } case UNION: { - int in1, in2, strin1, strin2; + bool in1, in2, strin1, strin2; Solid * tansol1 = 0, * tansol2 = 0; s1 -> RecTangentialSolid (p, tansol1, surfids, in1, strin1, eps); @@ -714,13 +714,13 @@ namespace netgen delete tansol1; delete tansol2; } - in = (in1 || in2); - strin = (strin1 || strin2); + in = in1 || in2; + strin = strin1 || strin2; break; } case SUB: { - int hin, hstrin; + bool hin, hstrin; Solid * tansol1; s1 -> RecTangentialSolid (p, tansol1, surfids, hin, hstrin, eps); @@ -742,22 +742,24 @@ namespace netgen - void Solid :: TangentialSolid2 (const Point<3> & p, - const Vec<3> & t, - Solid *& tansol, NgArray & surfids, double eps) const + unique_ptr Solid :: TangentialSolid2 (const Point<3> & p, + const Vec<3> & t, + NgArray & surfids, double eps) const { - int in, strin; + Solid * tansol = nullptr; + bool in, strin; surfids.SetSize (0); RecTangentialSolid2 (p, t, tansol, surfids, in, strin, eps); if (tansol) tansol -> GetTangentialSurfaceIndices2 (p, t, surfids, eps); + return unique_ptr (tansol); } void Solid :: RecTangentialSolid2 (const Point<3> & p, const Vec<3> & t, Solid *& tansol, NgArray & surfids, - int & in, int & strin, double eps) const + bool & in, bool & strin, double eps) const { - tansol = NULL; + tansol = nullptr; switch (op) { @@ -776,8 +778,8 @@ namespace netgen if (ist == DOES_INTERSECT) ist = prim->VecInSolid (p, t, eps); - in = (ist == IS_INSIDE || ist == DOES_INTERSECT); - strin = (ist == IS_INSIDE); + in = (ist == IS_INSIDE) || (ist == DOES_INTERSECT); + strin = ist == IS_INSIDE; if (ist == DOES_INTERSECT) { @@ -788,7 +790,7 @@ namespace netgen } case SECTION: { - int in1, in2, strin1, strin2; + bool in1, in2, strin1, strin2; Solid * tansol1, * tansol2; s1 -> RecTangentialSolid2 (p, t, tansol1, surfids, in1, strin1, eps); @@ -803,13 +805,13 @@ namespace netgen else if (tansol2) tansol = tansol2; } - in = (in1 && in2); - strin = (strin1 && strin2); + in = in1 && in2; + strin = strin1 && strin2; break; } case UNION: { - int in1, in2, strin1, strin2; + bool in1, in2, strin1, strin2; Solid * tansol1, * tansol2; s1 -> RecTangentialSolid2 (p, t, tansol1, surfids, in1, strin1, eps); @@ -824,13 +826,13 @@ namespace netgen else if (tansol2) tansol = tansol2; } - in = (in1 || in2); - strin = (strin1 || strin2); + in = in1 || in2; + strin = strin1 || strin2; break; } case SUB: { - int hin, hstrin; + bool hin, hstrin; Solid * tansol1; s1 -> RecTangentialSolid2 (p, t, tansol1, surfids, hin, hstrin, eps); @@ -856,25 +858,28 @@ namespace netgen - void Solid :: TangentialSolid3 (const Point<3> & p, - const Vec<3> & t, const Vec<3> & t2, - Solid *& tansol, NgArray & surfids, - double eps) const + unique_ptr Solid :: TangentialSolid3 (const Point<3> & p, + const Vec<3> & t, const Vec<3> & t2, + NgArray & surfids, + double eps) const { - int in, strin; + bool in, strin; + Solid * tansol = nullptr; surfids.SetSize (0); RecTangentialSolid3 (p, t, t2, tansol, surfids, in, strin, eps); if (tansol) tansol -> GetTangentialSurfaceIndices3 (p, t, t2, surfids, eps); + + return unique_ptr(tansol); } void Solid :: RecTangentialSolid3 (const Point<3> & p, const Vec<3> & t, const Vec<3> & t2, Solid *& tansol, NgArray & surfids, - int & in, int & strin, double eps) const + bool & in, bool & strin, double eps) const { - tansol = NULL; + tansol = nullptr; switch (op) { @@ -884,8 +889,8 @@ namespace netgen if (ist == DOES_INTERSECT) ist = prim->VecInSolid3 (p, t, t2, eps); - in = (ist == IS_INSIDE || ist == DOES_INTERSECT); - strin = (ist == IS_INSIDE); + in = (ist == IS_INSIDE) || (ist == DOES_INTERSECT); + strin = ist == IS_INSIDE; if (ist == DOES_INTERSECT) { @@ -896,7 +901,7 @@ namespace netgen } case SECTION: { - int in1, in2, strin1, strin2; + bool in1, in2, strin1, strin2; Solid * tansol1, * tansol2; s1 -> RecTangentialSolid3 (p, t, t2, tansol1, surfids, in1, strin1, eps); @@ -911,13 +916,13 @@ namespace netgen else if (tansol2) tansol = tansol2; } - in = (in1 && in2); - strin = (strin1 && strin2); + in = in1 && in2; + strin = strin1 && strin2; break; } case UNION: { - int in1, in2, strin1, strin2; + bool in1, in2, strin1, strin2; Solid * tansol1, * tansol2; s1 -> RecTangentialSolid3 (p, t, t2, tansol1, surfids, in1, strin1, eps); @@ -932,13 +937,13 @@ namespace netgen else if (tansol2) tansol = tansol2; } - in = (in1 || in2); - strin = (strin1 || strin2); + in = in1 || in2; + strin = strin1 || strin2; break; } case SUB: { - int hin, hstrin; + bool hin, hstrin; Solid * tansol1; s1 -> RecTangentialSolid3 (p, t, t2, tansol1, surfids, hin, hstrin, eps); @@ -967,12 +972,13 @@ namespace netgen - void Solid :: TangentialEdgeSolid (const Point<3> & p, - const Vec<3> & t, const Vec<3> & t2, const Vec<3> & m, - Solid *& tansol, NgArray & surfids, - double eps) const + unique_ptr Solid :: TangentialEdgeSolid (const Point<3> & p, + const Vec<3> & t, const Vec<3> & t2, const Vec<3> & m, + NgArray & surfids, + double eps) const { - int in, strin; + Solid * tansol = nullptr; + bool in, strin; surfids.SetSize (0); // *testout << "tangentialedgesolid,sol = " << (*this) << endl; @@ -980,12 +986,14 @@ namespace netgen if (tansol) tansol -> RecGetTangentialEdgeSurfaceIndices (p, t, t2, m, surfids, eps); + + return unique_ptr (tansol); } void Solid :: RecTangentialEdgeSolid (const Point<3> & p, const Vec<3> & t, const Vec<3> & t2, const Vec<3> & m, Solid *& tansol, NgArray & surfids, - int & in, int & strin, double eps) const + bool & in, bool & strin, double eps) const { tansol = NULL; @@ -1007,8 +1015,8 @@ namespace netgen // (*testout) << "ist2 = " << ist << endl; - in = (ist == IS_INSIDE || ist == DOES_INTERSECT); - strin = (ist == IS_INSIDE); + in = (ist == IS_INSIDE) || (ist == DOES_INTERSECT); + strin = ist == IS_INSIDE; if (ist == DOES_INTERSECT) { @@ -1019,7 +1027,7 @@ namespace netgen } case SECTION: { - int in1, in2, strin1, strin2; + bool in1, in2, strin1, strin2; Solid * tansol1, * tansol2; s1 -> RecTangentialEdgeSolid (p, t, t2, m, tansol1, surfids, in1, strin1, eps); @@ -1034,13 +1042,13 @@ namespace netgen else if (tansol2) tansol = tansol2; } - in = (in1 && in2); - strin = (strin1 && strin2); + in = in1 && in2; + strin = strin1 && strin2; break; } case UNION: { - int in1, in2, strin1, strin2; + bool in1, in2, strin1, strin2; Solid * tansol1, * tansol2; s1 -> RecTangentialEdgeSolid (p, t, t2, m, tansol1, surfids, in1, strin1, eps); @@ -1055,13 +1063,13 @@ namespace netgen else if (tansol2) tansol = tansol2; } - in = (in1 || in2); - strin = (strin1 || strin2); + in = in1 || in2; + strin = strin1 || strin2; break; } case SUB: { - int hin, hstrin; + bool hin, hstrin; Solid * tansol1; s1 -> RecTangentialEdgeSolid (p, t, t2, m, tansol1, surfids, hin, hstrin, eps); @@ -1097,29 +1105,31 @@ namespace netgen int Solid :: Edge (const Point<3> & p, const Vec<3> & v, double eps) const { - int in, strin, faces; + bool in, strin; + int faces; RecEdge (p, v, in, strin, faces, eps); return faces >= 2; } int Solid :: OnFace (const Point<3> & p, const Vec<3> & v, double eps) const { - int in, strin, faces; + bool in, strin; + int faces; RecEdge (p, v, in, strin, faces, eps); return faces >= 1; } void Solid :: RecEdge (const Point<3> & p, const Vec<3> & v, - int & in, int & strin, int & faces, double eps) const + bool & in, bool & strin, int & faces, double eps) const { switch (op) { case TERM: case TERM_REF: { INSOLID_TYPE ist = prim->VecInSolid (p, v, eps); - in = (ist == IS_INSIDE || ist == DOES_INTERSECT); - strin = (ist == IS_INSIDE); + in = (ist == IS_INSIDE) || (ist == DOES_INTERSECT); + strin = ist == IS_INSIDE; /* in = VectorIn (p, v); strin = VectorStrictIn (p, v); @@ -1145,7 +1155,8 @@ namespace netgen } case SECTION: { - int in1, in2, strin1, strin2, faces1, faces2; + bool in1, in2, strin1, strin2; + int faces1, faces2; s1 -> RecEdge (p, v, in1, strin1, faces1, eps); s2 -> RecEdge (p, v, in2, strin2, faces2, eps); @@ -1159,7 +1170,8 @@ namespace netgen } case UNION: { - int in1, in2, strin1, strin2, faces1, faces2; + bool in1, in2, strin1, strin2; + int faces1, faces2; s1 -> RecEdge (p, v, in1, strin1, faces1, eps); s2 -> RecEdge (p, v, in2, strin2, faces2, eps); @@ -1173,7 +1185,7 @@ namespace netgen } case SUB: { - int in1, strin1; + bool in1, strin1; s1 -> RecEdge (p, v, in1, strin1, faces, eps); in = !strin1; strin = !in1; diff --git a/libsrc/csg/solid.hpp b/libsrc/csg/solid.hpp index 3e884048..5f3d6688 100644 --- a/libsrc/csg/solid.hpp +++ b/libsrc/csg/solid.hpp @@ -117,13 +117,13 @@ namespace netgen unique_ptr TangentialSolid (const Point<3> & p, NgArray & surfids, double eps) const; /// compute localization in point p tangential to vector t - void TangentialSolid2 (const Point<3> & p, const Vec<3> & t, - Solid *& tansol, NgArray & surfids, double eps) const; + unique_ptr TangentialSolid2 (const Point<3> & p, const Vec<3> & t, + NgArray & surfids, double eps) const; /** compute localization in point p, with second order approximation to edge p + s t + s*s/2 t2 **/ - void TangentialSolid3 (const Point<3> & p, const Vec<3> & t, const Vec<3> & t2, - Solid *& tansol, NgArray & surfids, double eps) const; + unique_ptr TangentialSolid3 (const Point<3> & p, const Vec<3> & t, const Vec<3> & t2, + NgArray & surfids, double eps) const; @@ -133,9 +133,9 @@ namespace netgen p + s t + s*s/2 t2 + r m with first order **/ - void TangentialEdgeSolid (const Point<3> & p, const Vec<3> & t, const Vec<3> & t2, - const Vec<3> & m, - Solid *& tansol, NgArray & surfids, double eps) const; + unique_ptr TangentialEdgeSolid (const Point<3> & p, const Vec<3> & t, const Vec<3> & t2, + const Vec<3> & m, + NgArray & surfids, double eps) const; void CalcOnePrimitiveSpecialPoints (const Box<3> & box, NgArray > & pts) const; @@ -180,24 +180,24 @@ namespace netgen int & in, int & strin) const; /// void RecTangentialSolid (const Point<3> & p, Solid *& tansol, NgArray & surfids, - int & in, int & strin, double eps) const; + bool & in, bool & strin, double eps) const; void RecTangentialSolid2 (const Point<3> & p, const Vec<3> & vec, Solid *& tansol, NgArray & surfids, - int & in, int & strin, double eps) const; + bool & in, bool & strin, double eps) const; /// void RecTangentialSolid3 (const Point<3> & p, const Vec<3> & vec,const Vec<3> & vec2, Solid *& tansol, NgArray & surfids, - int & in, int & strin, double eps) const; + bool & in, bool & strin, double eps) const; /// void RecTangentialEdgeSolid (const Point<3> & p, const Vec<3> & t, const Vec<3> & t2, const Vec<3> & m, Solid *& tansol, NgArray & surfids, - int & in, int & strin, double eps) const; + bool & in, bool & strin, double eps) const; /// void RecEdge (const Point<3> & p, const Vec<3> & v, - int & in, int & strin, int & faces, double eps) const; + bool & in, bool & strin, int & faces, double eps) const; /// void CalcSurfaceInverseRec (int inv); /// diff --git a/libsrc/csg/specpoin.cpp b/libsrc/csg/specpoin.cpp index d4535e33..99c33377 100644 --- a/libsrc/csg/specpoin.cpp +++ b/libsrc/csg/specpoin.cpp @@ -1967,8 +1967,8 @@ namespace netgen (locsol, p, t, surfind2); */ - Solid * locsol2; - locsol -> TangentialSolid3 (p, t, t2, locsol2, surfind2, ideps*geomsize); + // Solid * locsol2; + auto locsol2 = locsol -> TangentialSolid3 (p, t, t2, surfind2, ideps*geomsize); if (!locsol2) continue; // locsol2 -> GetTangentialSurfaceIndices3 (p, t, t2, surfind2, 1e-9*geomsize); @@ -2014,10 +2014,10 @@ namespace netgen Vec<3> m2 = -m1; bool isface1 = 0, isface2 = 0; - Solid * locsol3; + // Solid * locsol3; // locsol2 -> TangentialSolid2 (p, m1, locsol3, surfind3, 1e-9*geomsize); - locsol -> TangentialEdgeSolid (p, t, t2, m1, locsol3, surfind3, ideps*geomsize); + auto locsol3 = locsol -> TangentialEdgeSolid (p, t, t2, m1, surfind3, ideps*geomsize); #ifdef DEVELOP (*testout) << "m1 = " << m1 << ", surfind3 = " << surfind3 << endl; #endif @@ -2025,10 +2025,10 @@ namespace netgen if (surfind3.Contains(surfind2[l])) isface1 = 1; - delete locsol3; + // delete locsol3; // locsol2 -> TangentialSolid2 (p, m2, locsol3, surfind3, 1e-9*geomsize); - locsol -> TangentialEdgeSolid (p, t, t2, m2, locsol3, surfind3, ideps*geomsize); + locsol3 = locsol -> TangentialEdgeSolid (p, t, t2, m2, surfind3, ideps*geomsize); #ifdef DEVELOP (*testout) << "m2 = " << m2 << ", surfind3 = " << surfind3 << endl; #endif @@ -2038,7 +2038,7 @@ namespace netgen if (surfind3.Contains(surfind2[l])) isface2 = 1; - delete locsol3; + // delete locsol3; if (isface1 != isface2) cnt_tang_faces++; @@ -2051,7 +2051,7 @@ namespace netgen if (cnt_tang_faces < 1) ok = false; - delete locsol2; + // delete locsol2; if (!ok) continue; } From 4cdaa6e3dfc48a90dd1d5f21ed52bb6ae8d12fb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20Sch=C3=B6berl?= Date: Fri, 16 Oct 2020 10:54:34 +0200 Subject: [PATCH 199/384] differentiate 1 correctly --- libsrc/csg/polyhedra.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsrc/csg/polyhedra.cpp b/libsrc/csg/polyhedra.cpp index c123458b..ae9e53bd 100644 --- a/libsrc/csg/polyhedra.cpp +++ b/libsrc/csg/polyhedra.cpp @@ -281,7 +281,7 @@ namespace netgen *testout << "tang in plane" << endl; double dlam1 = face.w1 * v; double dlam2 = face.w2 * v; - double dlam3 = 1-dlam1-dlam2; + double dlam3 = -dlam1-dlam2; if (printing) *testout << "dlam = " << dlam1 << " " << dlam2 << " " << dlam3 << endl; bool in1 = lam1 > eps_base1 || dlam1 > -eps_base1; From 1a051ec5556f57149259fb1590671e0bd51e9c04 Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Fri, 16 Oct 2020 12:05:03 +0200 Subject: [PATCH 200/384] export Polyhedra to Python and add test case --- libsrc/csg/python_csg.cpp | 29 +++++++++++++++++++++++++++++ tests/pytest/test_csg.py | 27 +++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 tests/pytest/test_csg.py diff --git a/libsrc/csg/python_csg.cpp b/libsrc/csg/python_csg.cpp index 09063e51..0954b2d6 100644 --- a/libsrc/csg/python_csg.cpp +++ b/libsrc/csg/python_csg.cpp @@ -354,6 +354,35 @@ When r =1, the truncated elliptic cone becomes an elliptic cylinder. When r tends to zero, the truncated elliptic cone tends to a full elliptic cone. However, when r = 0, the top part becomes a point(tip) and meshing fails! )raw_string"); + + m.def("Polyhedron", [](py::list points, py::list faces) + { + auto poly = new Polyhedra(); + for(auto p : points) + poly->AddPoint(py::cast>(p)); + int fnr = 0; + for(auto face : faces) + { + auto lface = py::cast(face); + if(py::len(lface) == 3) + poly->AddFace(py::cast(lface[0]), + py::cast(lface[1]), + py::cast(lface[2]), + fnr++); + else if(py::len(lface) == 4) + { + poly->AddFace(py::cast(lface[0]), + py::cast(lface[1]), + py::cast(lface[2]), + fnr); + poly->AddFace(py::cast(lface[0]), + py::cast(lface[2]), + py::cast(lface[3]), + fnr++); + } + } + return make_shared(new Solid(poly)); + }); m.def ("Or", FunctionPointer([](shared_ptr s1, shared_ptr s2) { diff --git a/tests/pytest/test_csg.py b/tests/pytest/test_csg.py new file mode 100644 index 00000000..55adcbbd --- /dev/null +++ b/tests/pytest/test_csg.py @@ -0,0 +1,27 @@ +from netgen.csg import * + +def test_2_polyhedra(): + geo = CSGeometry() + first = Polyhedron([(0,0,0), (0,1,0), (3,1,0), (3,0,0), + (0,1,1), (3,1,1), (3,0,1), (0,0,1)], + [(0,1,2,3), (1,4,5,2), (2,5,6,3), (3,6,7,0), + (0,7,4,1), (7,6,5,4)]) + # TODO: height = 0.1 not working! + height = 0.3 + second = Polyhedron([(0,0,1), (0,1,1), (3,1,1), (3,0,1), + (0,1,1+height), (3,1,1+height), + (3,0,1+height), (0,0,1+height)], + [(0,1,2,3), (1,4,5,2), (2,5,6,3), (3,6,7,0), + (0,7,4,1), (7,6,5,4)]) + + geo.Add(first) + geo.Add(second) + Draw(geo) + mesh = geo.GenerateMesh() + return mesh + + +if __name__ == "__main__": + from ngsolve import Mesh, Draw + mesh = Mesh(test_2_polyhedra()) + Draw(mesh) From 95b7720efd6057371c941b466b3f0a4dc5ff78c9 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Fri, 16 Oct 2020 14:22:01 +0200 Subject: [PATCH 201/384] optimize CalcPartition() and PartitionBoundary() --- libsrc/geom2d/genmesh2d.cpp | 50 +++++++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 16 deletions(-) diff --git a/libsrc/geom2d/genmesh2d.cpp b/libsrc/geom2d/genmesh2d.cpp index 6d00f1fe..6efbc39e 100644 --- a/libsrc/geom2d/genmesh2d.cpp +++ b/libsrc/geom2d/genmesh2d.cpp @@ -18,29 +18,43 @@ namespace netgen { double fperel, oldf, f; - int n = 10000; - - NgArray > xi(n); - NgArray hi(n); - - for (int i = 0; i < n; i++) + int n = 1; + NgArray > xi; + NgArray hi; + + bool not_fine_enough = true; + + while(not_fine_enough && n < 10000) + { + not_fine_enough = false; + n*=2; + + xi.SetSize(n); + hi.SetSize(n); + + for (int i = 0; i < n; i++) { - xi[i] = spline.GetPoint ( (i+0.5) / n ); - hi[i] = mesh.GetH (Point<3> (xi[i](0), xi[i](1), 0)); + xi[i] = spline.GetPoint ( (i+0.5) / n ); + hi[i] = mesh.GetH (Point<3> (xi[i](0), xi[i](1), 0)); } - // limit slope - double gradh = min(1/elto0,mp.grading); - for (int i = 0; i < n-1; i++) + // limit slope + double gradh = min(1/elto0,mp.grading); + for (int i = 0; i < n-1; i++) { - double hnext = hi[i] + gradh * (xi[i+1]-xi[i]).Length(); - hi[i+1] = min(hi[i+1], hnext); + double hnext = hi[i] + gradh * (xi[i+1]-xi[i]).Length(); + if(hnext > 2*hi[i]) + not_fine_enough = true; + hi[i+1] = min(hi[i+1], hnext); } - for (int i = n-1; i > 1; i--) + for (int i = n-1; i > 1; i--) { - double hnext = hi[i] + gradh * (xi[i-1]-xi[i]).Length(); - hi[i-1] = min(hi[i-1], hnext); + double hnext = hi[i] + gradh * (xi[i-1]-xi[i]).Length(); + if(hnext > 2*hi[i]) + not_fine_enough = true; + hi[i-1] = min(hi[i-1], hnext); } + } points.SetSize (0); @@ -227,6 +241,10 @@ namespace netgen mesh2d.RestrictLocalHLine (Point<3>(p1(0),p1(1),0), Point<3>(p2(0),p2(1),0), len/mp.segmentsperedge); + // skip curvature restrictions for straight lines + if(spline.MaxCurvature()==0) + continue; + double hcurve = min (spline.hmax, h/spline.reffak); double hl = GetDomainMaxh (spline.leftdom); if (hl > 0) hcurve = min2 (hcurve, hl); From 19ebc915c8dbb0780e1f74770eaaa561da59dc33 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Wed, 14 Oct 2020 18:40:23 +0200 Subject: [PATCH 202/384] CSG2d - faster AddIntersections (search tree per loop) --- libsrc/geom2d/csg2d.cpp | 146 +++++++++++++++++++++++----------------- 1 file changed, 85 insertions(+), 61 deletions(-) diff --git a/libsrc/geom2d/csg2d.cpp b/libsrc/geom2d/csg2d.cpp index e1168d53..f46a813d 100644 --- a/libsrc/geom2d/csg2d.cpp +++ b/libsrc/geom2d/csg2d.cpp @@ -670,55 +670,49 @@ void AddIntersectionPoint(Edge edgeP, Edge edgeQ, IntersectionType i, double alp } } -void ComputeIntersections(Solid2d & s1, Solid2d & s2) +void ComputeIntersections(Loop & l1, Loop & l2) { - static Timer tall("ComputeIntersections"); RegionTimer rtall(tall); - static Timer t_tree("build search trees"); static Timer t_intersect("find intersections"); static Timer t_split("split splines"); - auto & PP = s1.polys; - auto & QQ = s2.polys; t_intersect.Start(); - for (Loop& P : PP) - for (Edge edgeP : P.Edges(SOURCE)) - for (Loop& Q : QQ) - for (Edge edgeQ : Q.Edges(SOURCE)) + for (Edge edgeP : l1.Edges(SOURCE)) + for (Edge edgeQ : l2.Edges(SOURCE)) + { + double alpha = 0.0; + double beta = 0.0; + IntersectionType i = intersect(edgeP, edgeQ, alpha, beta); + AddIntersectionPoint(edgeP, edgeQ, i, alpha, beta); + if(i==X_INTERSECTION && (edgeP.v0->spline || edgeQ.v0->spline)) + { + double alpha1 = alpha+1e2*EPSILON; + double beta1 = 0.0; //beta+1e2*EPSILON; + + // search for possible second intersection + i = intersect(edgeP, edgeQ, alpha1, beta1); + // cout << "second intersection " << i << ',' << alpha1 << ',' << beta1 << ',' << alpha1-alpha << ',' << beta1-beta << endl; + if(i!=NO_INTERSECTION && alpha+EPSILONspline || edgeQ.v0->spline)) + // Add midpoint of two intersection points to avoid false overlap detection of splines + // TODO: Check if this is really necessary + auto alpha_mid = 0.5*(alpha+alpha1); + auto beta_mid = 0.5*(beta+beta1); + Point<2> MP; + if(edgeP.v0->spline) { - double alpha1 = alpha+1e2*EPSILON; - double beta1 = 0.0; //beta+1e2*EPSILON; - - // search for possible second intersection - i = intersect(edgeP, edgeQ, alpha1, beta1); - // cout << "second intersection " << i << ',' << alpha1 << ',' << beta1 << ',' << alpha1-alpha << ',' << beta1-beta << endl; - if(i!=NO_INTERSECTION && alpha+EPSILON MP; - if(edgeP.v0->spline) - { - MP = edgeP.v0->spline->GetPoint(alpha_mid); - edgeP.v0->Insert(MP, alpha_mid); - } - else - MP = edgeQ.v0->spline->GetPoint(beta_mid); - - if(edgeQ.v0->spline) - edgeQ.v0->Insert(MP, beta_mid); - - AddIntersectionPoint(edgeP, edgeQ, i, alpha1, beta1); - } + MP = edgeP.v0->spline->GetPoint(alpha_mid); + edgeP.v0->Insert(MP, alpha_mid); } + else + MP = edgeQ.v0->spline->GetPoint(beta_mid); + + if(edgeQ.v0->spline) + edgeQ.v0->Insert(MP, beta_mid); + + AddIntersectionPoint(edgeP, edgeQ, i, alpha1, beta1); } + } + } t_intersect.Stop(); RegionTimer rt_split(t_split); @@ -743,12 +737,19 @@ void ComputeIntersections(Solid2d & s1, Solid2d & s2) } while(!curr->is_source); }; - for (Loop& P : PP) - for (Vertex* v : P.Vertices(SOURCE)) - split_spline_at_vertex(v); - for (Loop& Q : QQ) - for (Vertex* v : Q.Vertices(SOURCE)) - split_spline_at_vertex(v); + for (Vertex* v : l1.Vertices(SOURCE)) + split_spline_at_vertex(v); + for (Vertex* v : l2.Vertices(SOURCE)) + split_spline_at_vertex(v); +} + +void ComputeIntersections(Solid2d & s1, Solid2d & s2) +{ + static Timer tall("ComputeIntersections"); RegionTimer rtall(tall); + + for (Loop& l1 : s1.polys) + for (Loop& l2 : s2.polys) + ComputeIntersections(l1, l2); } enum RelativePositionType @@ -1251,20 +1252,25 @@ void CleanUpResult(Solid2d & sr) RR.RemoveElement(i); } +void RemoveDuplicates(Loop & poly) +{ + if(poly.first==nullptr) + return; + + Vertex * last = poly.first->prev; + for(auto v : poly.Vertices(ALL)) + { + if(Dist2(*v, *last)prev; - for(auto v : poly.Vertices(ALL)) - { - if(Dist2(*v, *last) CSG2d :: GenerateSplineGeometry() static Timer t_is_inside("is inside check"); static Timer t_segments("add segments"); static Timer t_intersections("add intersections"); + static Timer t_segtree("seg trees"); RegionTimer rt(tall); struct Seg @@ -1756,18 +1771,27 @@ shared_ptr CSG2d :: GenerateSplineGeometry() box.Add(sbox.PMax()); } - netgen::BoxTree <2, int> solid_tree(box); + netgen::BoxTree <2> solid_tree(box); + Array> loop_list; for(auto i : Range(solids)) - solid_tree.Insert(solids[i].GetBoundingBox(), i); + for(auto li : Range(solids[i].polys)) + { + solid_tree.Insert(solids[i].polys[li].GetBoundingBox(), loop_list.Size()); + loop_list.Append(INT<2>(i, li)); + } for(auto i1 : Range(solids)) + for(auto li1 : Range(solids[i1].polys)) { - auto sbox = solids[i1].GetBoundingBox(); - solid_tree.GetFirstIntersecting(sbox.PMin(), sbox.PMax(), [&] (int i2) + auto & poly1 = solids[i1].polys[li1]; + auto box = poly1.GetBoundingBox(); + solid_tree.GetFirstIntersecting(box.PMin(), box.PMax(), [&] (int ii) { + auto i2 = loop_list[ii][0]; + auto li2 = loop_list[ii][1]; if(i1 Date: Thu, 15 Oct 2020 17:51:05 +0200 Subject: [PATCH 203/384] csg2d - fix bug with splines --- libsrc/geom2d/csg2d.cpp | 186 ++++++++++++++++++++++++---------------- libsrc/geom2d/csg2d.hpp | 4 + 2 files changed, 114 insertions(+), 76 deletions(-) diff --git a/libsrc/geom2d/csg2d.cpp b/libsrc/geom2d/csg2d.cpp index f46a813d..28855310 100644 --- a/libsrc/geom2d/csg2d.cpp +++ b/libsrc/geom2d/csg2d.cpp @@ -670,58 +670,35 @@ void AddIntersectionPoint(Edge edgeP, Edge edgeQ, IntersectionType i, double alp } } -void ComputeIntersections(Loop & l1, Loop & l2) +void RemoveDuplicates(Loop & poly) { - static Timer t_intersect("find intersections"); - static Timer t_split("split splines"); + if(poly.first==nullptr) + return; - t_intersect.Start(); - for (Edge edgeP : l1.Edges(SOURCE)) - for (Edge edgeQ : l2.Edges(SOURCE)) - { - double alpha = 0.0; - double beta = 0.0; - IntersectionType i = intersect(edgeP, edgeQ, alpha, beta); - AddIntersectionPoint(edgeP, edgeQ, i, alpha, beta); - if(i==X_INTERSECTION && (edgeP.v0->spline || edgeQ.v0->spline)) - { - double alpha1 = alpha+1e2*EPSILON; - double beta1 = 0.0; //beta+1e2*EPSILON; + Vertex * last = poly.first->prev; + for(auto v : poly.Vertices(ALL)) + { + if(Dist2(*v, *last) MP; - if(edgeP.v0->spline) - { - MP = edgeP.v0->spline->GetPoint(alpha_mid); - edgeP.v0->Insert(MP, alpha_mid); - } - else - MP = edgeQ.v0->spline->GetPoint(beta_mid); +void RemoveDuplicates(Solid2d & sr) +{ + static Timer tall("RemoveDuplicates"); RegionTimer rtall(tall); + for(auto & poly : sr.polys) + RemoveDuplicates(poly); +} - if(edgeQ.v0->spline) - edgeQ.v0->Insert(MP, beta_mid); - - AddIntersectionPoint(edgeP, edgeQ, i, alpha1, beta1); - } - } - } - t_intersect.Stop(); - - RegionTimer rt_split(t_split); +void SplitSplines( Loop & l) +{ // Split splines at new vertices - auto split_spline_at_vertex = [](Vertex *v) + for (Vertex* v : l.Vertices(SOURCE)) { if(!v->spline) - return; + continue; Spline ori{*v->spline}; Vertex * curr = v; do @@ -732,15 +709,69 @@ void ComputeIntersections(Loop & l1, Loop & l2) double t0 = curr->is_source ? 0.0 : curr->lam; double t1 = next->is_source ? 1.0 : next->lam; curr->spline = Split(ori, t0, t1); + curr->lam = -1; + curr->is_source = true; } curr = next; } while(!curr->is_source); }; + RemoveDuplicates(l); +} - for (Vertex* v : l1.Vertices(SOURCE)) - split_spline_at_vertex(v); - for (Vertex* v : l2.Vertices(SOURCE)) - split_spline_at_vertex(v); +void ComputeIntersections(Edge edgeP , Loop & l2) +{ + for (Edge edgeQ : l2.Edges(SOURCE)) + { + double alpha = 0.0; + double beta = 0.0; + IntersectionType i = intersect(edgeP, edgeQ, alpha, beta); + AddIntersectionPoint(edgeP, edgeQ, i, alpha, beta); + if(i==X_INTERSECTION && (edgeP.v0->spline || edgeQ.v0->spline)) + { + double alpha1 = alpha+1e2*EPSILON; + double beta1 = 0.0; //beta+1e2*EPSILON; + + // search for possible second intersection + i = intersect(edgeP, edgeQ, alpha1, beta1); + // cout << "second intersection " << i << ',' << alpha1 << ',' << beta1 << ',' << alpha1-alpha << ',' << beta1-beta << endl; + if(i!=NO_INTERSECTION && alpha+EPSILON MP; + if(edgeP.v0->spline) + { + MP = edgeP.v0->spline->GetPoint(alpha_mid); + edgeP.v0->Insert(MP, alpha_mid); + } + else + MP = edgeQ.v0->spline->GetPoint(beta_mid); + + if(edgeQ.v0->spline) + edgeQ.v0->Insert(MP, beta_mid); + + AddIntersectionPoint(edgeP, edgeQ, i, alpha1, beta1); + } + } + } +} + +void ComputeIntersections(Loop & l1, Loop & l2) +{ + static Timer t_intersect("find intersections"); + static Timer t_split("split splines"); + + t_intersect.Start(); + for (Edge edgeP : l1.Edges(SOURCE)) + ComputeIntersections(edgeP, l2); + t_intersect.Stop(); + + RegionTimer rt_split(t_split); + + SplitSplines(l1); + SplitSplines(l2); } void ComputeIntersections(Solid2d & s1, Solid2d & s2) @@ -748,8 +779,15 @@ void ComputeIntersections(Solid2d & s1, Solid2d & s2) static Timer tall("ComputeIntersections"); RegionTimer rtall(tall); for (Loop& l1 : s1.polys) - for (Loop& l2 : s2.polys) - ComputeIntersections(l1, l2); + for (Edge edgeP : l1.Edges(SOURCE)) + for (Loop& l2 : s2.polys) + ComputeIntersections(edgeP, l2); + + for (Loop& l1 : s1.polys) + SplitSplines(l1); + + for (Loop& l2 : s2.polys) + SplitSplines(l2); } enum RelativePositionType @@ -1109,13 +1147,30 @@ next_P: ; if (split[1].find(I_Q) != split[1].end()) { // compute areas to compare local orientation - double sP = Area( *I_P->prev, *I_P, *I_P->next); - double sQ = Area( *I_Q->prev, *I_Q, *I_Q->next); + Point<2> p_prev = *I_P->prev; + if(I_P->prev->spline) + p_prev = I_P->prev->spline->TangentPoint(); + + Point<2> p_next = *I_P->next; + if(I_P->spline) + p_next = I_P->spline->TangentPoint(); + + Point<2> q_prev = *I_Q->prev; + if(I_Q->prev->spline) + q_prev = I_Q->prev->spline->TangentPoint(); + + Point<2> q_next = *I_Q->next; + if(I_Q->spline) + q_next = I_Q->spline->TangentPoint(); + + + double sP = Area( p_prev, *I_P, p_next ); + double sQ = Area( q_prev, *I_Q, q_next ); // add duplicate vertices to P and Q - auto V_P = I_P->Insert(*I_P); + auto V_P = I_P->Insert(*I_P, I_P->lam); V_P->spline = I_P->spline; - auto V_Q = I_Q->Insert(*I_Q); + auto V_Q = I_Q->Insert(*I_Q, I_Q->lam); V_Q->spline = I_Q->spline; // link vertices correctly @@ -1252,27 +1307,6 @@ void CleanUpResult(Solid2d & sr) RR.RemoveElement(i); } -void RemoveDuplicates(Loop & poly) -{ - if(poly.first==nullptr) - return; - - Vertex * last = poly.first->prev; - for(auto v : poly.Vertices(ALL)) - { - if(Dist2(*v, *last) CSG2d :: GenerateSplineGeometry() }); } + t_intersections.Stop(); // Add geometry points to SplineGeometry diff --git a/libsrc/geom2d/csg2d.hpp b/libsrc/geom2d/csg2d.hpp index 16175f1e..fbb4b8b0 100644 --- a/libsrc/geom2d/csg2d.hpp +++ b/libsrc/geom2d/csg2d.hpp @@ -609,7 +609,11 @@ struct Loop static Timer tall("Loop::GetBoundingBox"); RegionTimer rt(tall); bbox = make_unique>(Box<2>::EMPTY_BOX); for(auto v : Vertices(ALL)) + { bbox->Add(*v); + if(v->spline) + bbox->Add(v->spline->TangentPoint()); + } } return *bbox; } From 4c15146df9da9b6ee4af5c5fc4500b38d10f2215 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Fri, 16 Oct 2020 14:30:38 +0200 Subject: [PATCH 204/384] fix windows build error --- libsrc/geom2d/csg2d.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libsrc/geom2d/csg2d.cpp b/libsrc/geom2d/csg2d.cpp index 28855310..4fa163d9 100644 --- a/libsrc/geom2d/csg2d.cpp +++ b/libsrc/geom2d/csg2d.cpp @@ -12,6 +12,7 @@ namespace netgen { +using ngcore::INT; constexpr static double EPSILON=0.000000001; From f66d8bd54eb4b427be7fee25cf1efd1d6e9fabef Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Fri, 16 Oct 2020 14:44:51 +0200 Subject: [PATCH 205/384] Revert "optimize CalcPartition() and PartitionBoundary()" This reverts commit 95b7720efd6057371c941b466b3f0a4dc5ff78c9. --- libsrc/geom2d/genmesh2d.cpp | 50 ++++++++++++------------------------- 1 file changed, 16 insertions(+), 34 deletions(-) diff --git a/libsrc/geom2d/genmesh2d.cpp b/libsrc/geom2d/genmesh2d.cpp index 6efbc39e..6d00f1fe 100644 --- a/libsrc/geom2d/genmesh2d.cpp +++ b/libsrc/geom2d/genmesh2d.cpp @@ -18,43 +18,29 @@ namespace netgen { double fperel, oldf, f; - int n = 1; - NgArray > xi; - NgArray hi; - - bool not_fine_enough = true; - - while(not_fine_enough && n < 10000) - { - not_fine_enough = false; - n*=2; - - xi.SetSize(n); - hi.SetSize(n); - - for (int i = 0; i < n; i++) + int n = 10000; + + NgArray > xi(n); + NgArray hi(n); + + for (int i = 0; i < n; i++) { - xi[i] = spline.GetPoint ( (i+0.5) / n ); - hi[i] = mesh.GetH (Point<3> (xi[i](0), xi[i](1), 0)); + xi[i] = spline.GetPoint ( (i+0.5) / n ); + hi[i] = mesh.GetH (Point<3> (xi[i](0), xi[i](1), 0)); } - // limit slope - double gradh = min(1/elto0,mp.grading); - for (int i = 0; i < n-1; i++) + // limit slope + double gradh = min(1/elto0,mp.grading); + for (int i = 0; i < n-1; i++) { - double hnext = hi[i] + gradh * (xi[i+1]-xi[i]).Length(); - if(hnext > 2*hi[i]) - not_fine_enough = true; - hi[i+1] = min(hi[i+1], hnext); + double hnext = hi[i] + gradh * (xi[i+1]-xi[i]).Length(); + hi[i+1] = min(hi[i+1], hnext); } - for (int i = n-1; i > 1; i--) + for (int i = n-1; i > 1; i--) { - double hnext = hi[i] + gradh * (xi[i-1]-xi[i]).Length(); - if(hnext > 2*hi[i]) - not_fine_enough = true; - hi[i-1] = min(hi[i-1], hnext); + double hnext = hi[i] + gradh * (xi[i-1]-xi[i]).Length(); + hi[i-1] = min(hi[i-1], hnext); } - } points.SetSize (0); @@ -241,10 +227,6 @@ namespace netgen mesh2d.RestrictLocalHLine (Point<3>(p1(0),p1(1),0), Point<3>(p2(0),p2(1),0), len/mp.segmentsperedge); - // skip curvature restrictions for straight lines - if(spline.MaxCurvature()==0) - continue; - double hcurve = min (spline.hmax, h/spline.reffak); double hl = GetDomainMaxh (spline.leftdom); if (hl > 0) hcurve = min2 (hcurve, hl); From 97dfecd04018f5716557926d7a2f18889739e4e1 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Fri, 16 Oct 2020 17:58:52 +0200 Subject: [PATCH 206/384] fix test --- tests/pytest/test_csg.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/pytest/test_csg.py b/tests/pytest/test_csg.py index 55adcbbd..7cfc9331 100644 --- a/tests/pytest/test_csg.py +++ b/tests/pytest/test_csg.py @@ -16,7 +16,6 @@ def test_2_polyhedra(): geo.Add(first) geo.Add(second) - Draw(geo) mesh = geo.GenerateMesh() return mesh From 8ba6bad6fd7ebcb4cda631acbd9fcae01f2fb9a7 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Fri, 16 Oct 2020 18:28:09 +0200 Subject: [PATCH 207/384] Delaunay for 2d mesh generation Squashed commit of the following: commit 84f36ffeb409f5fddb389c75ee48b4872b516ae9 Author: Matthias Hochsteger Date: Fri Oct 16 18:27:15 2020 +0200 revert change in spline partitioning commit d4aef23a22a9beb26c4453267c99dd7533174ced Merge: 15a467aa 97dfecd0 Author: Matthias Hochsteger Date: Fri Oct 16 17:59:00 2020 +0200 Merge branch 'master' into delaunay2d commit 15a467aa7f7cb09f9ea3d984905fe3da69f0b238 Author: Matthias Hochsteger Date: Fri Oct 16 17:44:31 2020 +0200 delaunay2d - fix trig orientation commit be223412ad972722a51b64a5bccf7ca2bec566c8 Author: Matthias Hochsteger Date: Fri Oct 16 17:29:46 2020 +0200 fix delaunay swapping commit 48b95ae2ee1cbabcfae79dfd1cb7af1fd69d77f3 Author: Matthias Hochsteger Date: Fri Oct 16 17:27:51 2020 +0200 testout only with debug settings commit d82b7a7cecb6f65f42b79b666fc58d0116dc0365 Author: Matthias Hochsteger Date: Fri Oct 16 16:37:10 2020 +0200 delaunay only for large domains commit 1f51eaca1ff7a3777e4f32ba9e35e48d496a2854 Author: Matthias Hochsteger Date: Fri Oct 16 16:21:33 2020 +0200 compress points in delaunay commit 20a223f36f3912a208db80c717d9dd87851ba43f Merge: 2446b746 4c15146d Author: Matthias Hochsteger Date: Fri Oct 16 14:31:14 2020 +0200 Merge branch 'master' into delaunay2d commit 2446b74687ee56633a86e748e85343919edbd5ad Author: Matthias Hochsteger Date: Fri Oct 16 14:22:01 2020 +0200 optimize CalcPartition() and PartitionBoundary() commit 3baa58833348a72f16853530a5d17e73424186df Author: Matthias Hochsteger Date: Fri Oct 16 12:24:17 2020 +0200 MeshingParameters - delaunay2d option (default is off) commit e79b113dde9b9c4c5b92239817c6058ca468c319 Author: Matthias Hochsteger Date: Thu Oct 15 16:12:45 2020 +0200 fix windows build error commit 92c7b9c1ed4016458980bbc21c61dae07f4444c7 Author: Matthias Hochsteger Date: Thu Oct 15 17:51:44 2020 +0200 delaunay bugfix commit 6880194107819cfb2d23206e7e0f48ff5aa3fc10 Author: Matthias Hochsteger Date: Thu Oct 15 17:51:05 2020 +0200 csg2d - fix bug with splines commit 1d9baa299d49e1f6fa16f4368885601ed01c5de7 Author: Matthias Hochsteger Date: Wed Oct 14 18:40:23 2020 +0200 CSG2d - faster AddIntersections (search tree per loop) commit 2679ef0dee10cdf486441af47ca4c081aa7eb50b Author: Matthias Hochsteger Date: Wed Oct 14 17:13:17 2020 +0200 bounding box for Loop commit 894c6345b737693e32cbda368e56f56764e11085 Author: Matthias Hochsteger Date: Wed Oct 14 12:48:51 2020 +0200 remove debug check, output in blockfill commit 2b0a0892c41e746b12e5e852cdb138acd3d2c4e3 Author: Matthias Hochsteger Date: Wed Oct 14 12:40:53 2020 +0200 compress mesh after delaunay commit 1de33c87eee3199d4d9b18544f66e53329b47a2f Author: Matthias Hochsteger Date: Wed Oct 14 12:37:07 2020 +0200 revert change in improve2d commit 41a60e89533e94b93b92202ac17852d3aee9acbb Author: Matthias Hochsteger Date: Wed Oct 14 12:25:07 2020 +0200 cleanup delaunay2d commit c16aae324969cd5a90748953019933690d013337 Author: Matthias Hochsteger Date: Wed Oct 14 11:39:56 2020 +0200 sunburst chart - tooltip formatting commit 4d61e1fdeab302ba357904f22f951361935791f0 Author: Matthias Hochsteger Date: Wed Oct 14 11:03:37 2020 +0200 delaunay seems to work commit 8bd43f54d1efd6862f1b403cdb6c8ce9b5f7b3c6 Merge: 90ac7adb 25efdadd Author: Matthias Hochsteger Date: Tue Oct 13 12:08:01 2020 +0200 Merge remote-tracking branch 'gitlab/master' into delaunay2d commit 90ac7adb562cf2402345c5dfb4281bd097b5d62d Author: Matthias Hochsteger Date: Tue Oct 13 12:04:49 2020 +0200 fix Loop::operator= commit 1eb4f2de3b6576f503a073011a208fa8f609524e Author: Matthias Hochsteger Date: Tue Oct 13 12:04:13 2020 +0200 more statistics in sunburst chart commit db8b97ffbbc7db2a3413c4f8a5528eebe3488d57 Author: Matthias Hochsteger Date: Tue Oct 13 11:17:28 2020 +0200 more work on delaunay2d commit eaa675f2351252b5fde423f241b10e231d1eb97e Merge: 0eb9f9bd 8f837cb9 Author: Matthias Hochsteger Date: Mon Oct 12 12:51:31 2020 +0200 Merge remote-tracking branch 'gitlab/delaunay2d' into delaunay2d commit 0eb9f9bd1c31a0e3c3c796c9280b1c1d007ace26 Author: Matthias Hochsteger Date: Mon Oct 12 12:50:10 2020 +0200 further csg2d optimization commit 8f837cb9a281acca7c33159985da3b6992fe638f Author: Matthias Hochsteger Date: Tue Oct 6 19:02:31 2020 +0200 csg2d - optimize Loop::operator= commit 7bb4f16b886b20902b0d3563716055fc1734d47e Author: Matthias Hochsteger Date: Tue Oct 6 10:28:20 2020 +0200 csg2d performance (search tree, inside tests) commit 2c9ebce04d7989223327a1875e1b65bf180c95f5 Author: Matthias Hochsteger Date: Fri Oct 2 16:33:24 2020 +0200 [WIP] delaunay2d commit 749df2311a3ac1976faaa9f0b60846709a2087b9 Author: Matthias Hochsteger Date: Thu Oct 1 11:36:03 2020 +0200 something commit cda9fffde33a86b71467debb86848fdb9cfbf80c Author: Matthias Hochsteger Date: Wed Sep 30 12:06:53 2020 +0200 delaunay2d - fix size of starting trig --- libsrc/geom2d/genmesh2d.cpp | 55 ++- libsrc/meshing/delaunay2d.cpp | 796 +++++++++++++++++++++++++-------- libsrc/meshing/meshtype.hpp | 4 +- libsrc/meshing/python_mesh.hpp | 5 + 4 files changed, 656 insertions(+), 204 deletions(-) diff --git a/libsrc/geom2d/genmesh2d.cpp b/libsrc/geom2d/genmesh2d.cpp index 6d00f1fe..905f09b6 100644 --- a/libsrc/geom2d/genmesh2d.cpp +++ b/libsrc/geom2d/genmesh2d.cpp @@ -392,10 +392,16 @@ namespace netgen shared_ptr & mesh, MeshingParameters & mp) { + static Timer tall("MeshFromSpline2D"); RegionTimer rtall(tall); + static Timer t_h("SetH"); + static Timer t_tensor("tensor domain meshing"); + static Timer t_part_boundary("PartitionBoundary"); + static Timer t_hpref("mark hpref points"); PrintMessage (1, "Generate Mesh from spline geometry"); Box<2> bbox = geometry.GetBoundingBox (); + t_h.Start(); if (bbox.Diam() < mp.maxh) mp.maxh = bbox.Diam(); @@ -412,11 +418,14 @@ namespace netgen + t_part_boundary.Start(); geometry.PartitionBoundary (mp, mp.maxh, *mesh); + t_part_boundary.Stop(); PrintMessage (3, "Boundary mesh done, np = ", mesh->GetNP()); + t_hpref.Start(); // marks mesh points for hp-refinement for (int i = 0; i < geometry.GetNP(); i++) if (geometry.GetPoint(i).hpref) @@ -434,6 +443,7 @@ namespace netgen } (*mesh)[mpi].Singularity(geometry.GetPoint(i).hpref); } + t_hpref.Stop(); int maxdomnr = 0; @@ -459,6 +469,7 @@ namespace netgen mesh->SetBCName ( sindex, geometry.GetBCName( sindex+1 ) ); mesh->CalcLocalH(mp.grading); + t_h.Stop(); int bnp = mesh->GetNP(); // boundary points auto BndPntRange = mesh->Points().Range(); @@ -469,6 +480,7 @@ namespace netgen for (int domnr = 1; domnr <= maxdomnr; domnr++) if (geometry.GetDomainTensorMeshing (domnr)) { // tensor product mesh + RegionTimer rt(t_tensor); NgArray nextpi(bnp); NgArray si1(bnp), si2(bnp); @@ -556,8 +568,10 @@ namespace netgen + static Timer t_domain("Mesh domain"); for (int domnr = 1; domnr <= maxdomnr; domnr++) { + RegionTimer rt(t_domain); if (geometry.GetDomainTensorMeshing (domnr)) continue; double h = mp.maxh; @@ -573,16 +587,26 @@ namespace netgen Meshing2 meshing (geometry, mp, Box<3> (pmin, pmax)); - NgArray compress(bnp); + NgArray compress(mesh->GetNP()); compress = -1; int cnt = 0; - for (PointIndex pi : BndPntRange) - if ( (*mesh)[pi].GetLayer() == geometry.GetDomainLayer(domnr)) - { - meshing.AddPoint ((*mesh)[pi], pi); - cnt++; - compress[pi] = cnt; - } + + for (SegmentIndex si = 0; si < mesh->GetNSeg(); si++) + { + const auto & s = (*mesh)[si]; + if ( s.domin==domnr || s.domout==domnr ) + { + for (auto pi : {s[0], s[1]}) + { + if(compress[pi]==-1) + { + meshing.AddPoint((*mesh)[pi], pi); + cnt++; + compress[pi] = cnt; + } + } + } + } PointGeomInfo gi; gi.trignum = 1; @@ -600,12 +624,15 @@ namespace netgen } } - // not complete, use at own risk ... - // meshing.Delaunay(*mesh, domnr, mp); - mp.checkoverlap = 0; - auto res = meshing.GenerateMesh (*mesh, mp, h, domnr); - if (res != 0) - throw NgException("meshing failed"); + if(mp.delaunay2d && cnt>100) + meshing.Delaunay(*mesh, domnr, mp); + else + { + // mp.checkoverlap = 0; + auto res = meshing.GenerateMesh (*mesh, mp, h, domnr); + if (res != 0) + throw NgException("meshing failed"); + } for (SurfaceElementIndex sei = oldnf; sei < mesh->GetNSE(); sei++) (*mesh)[sei].SetIndex (domnr); diff --git a/libsrc/meshing/delaunay2d.cpp b/libsrc/meshing/delaunay2d.cpp index a61016e2..66b22708 100644 --- a/libsrc/meshing/delaunay2d.cpp +++ b/libsrc/meshing/delaunay2d.cpp @@ -1,34 +1,52 @@ #include #include "meshing.hpp" +#include + + // not yet working .... namespace netgen { + using ngcore::INT; + extern void Optimize2d (Mesh & mesh, MeshingParameters & mp); + static inline Point<2> P2( Point<3> p ) + { + return {p[0], p[1]}; + } + + static inline Point<3> P3( Point<2> p ) + { + return {p[0], p[1], 0}; + } class DelaunayTrig { PointIndex pnums[3]; - Point<3> c; + Point<2> c; + public: double r; double rad2; - public: - DelaunayTrig () { ; } + DelaunayTrig () = default; DelaunayTrig (int p1, int p2, int p3) - { pnums[0] = p1; pnums[1] = p2; pnums[2] = p3; } + { + pnums[0] = p1; + pnums[1] = p2; + pnums[2] = p3; + } PointIndex & operator[] (int j) { return pnums[j]; } const PointIndex & operator[] (int j) const { return pnums[j]; } void CalcCenter (Mesh & mesh) { - Point<3> p1 = mesh[pnums[0]]; - Point<3> p2 = mesh[pnums[1]]; - Point<3> p3 = mesh[pnums[2]]; - Vec<3> v1 = p2-p1; - Vec<3> v2 = p3-p1; + Point<2> p1 = P2(mesh[pnums[0]]); + Point<2> p2 = P2(mesh[pnums[1]]); + Point<2> p3 = P2(mesh[pnums[2]]); + Vec<2> v1 = p2-p1; + Vec<2> v2 = p3-p1; Mat<2,2> mat, inv; mat(0,0) = v1*v1; mat(0,1) = v1*v2; @@ -45,9 +63,301 @@ namespace netgen r = sqrt(rad2); } - Point<3> Center() const { return c; } + Point<2> Center() const { return c; } double Radius2() const { return rad2; } - Box<3> BoundingBox() const { return Box<3> (c-Vec<3>(r,r,0.1), c+Vec<3>(r,r,0.1)); } + Box<2> BoundingBox() const { return Box<2> (c-Vec<2>(r,r), c+Vec<2>(r,r)); } + }; + + class DelaunayMesh + { + ngcore::ClosedHashTable, INT<2>> edge_to_trig; + Array trigs; + unique_ptr> tree; + Mesh & mesh; + + Array closeels; + Array intersecting; + Array> edges; + + int GetNeighbour( int eli, int edge ) + { + auto p0 = trigs[eli][(edge+1)%3]; + auto p1 = trigs[eli][(edge+2)%3]; + if(p1 hash = {p0,p1}; + if(!edge_to_trig.Used(hash)) + return -1; + + auto i2 = edge_to_trig.Get({p0,p1}); + + return i2[0] == eli ? i2[1] : i2[0]; + } + + void SetNeighbour( int eli, int edge ) + { + auto p0 = trigs[eli][(edge+1)%3]; + auto p1 = trigs[eli][(edge+2)%3]; + if(p1 hash = {p0,p1}; + if(!edge_to_trig.Used(hash)) + edge_to_trig[hash] = {eli, -1}; + else + { + + auto i2 = edge_to_trig.Get({p0,p1}); + + if(i2[0]==-1) + i2[0] = eli; + else + { + if(i2[1]==-1) + i2[1] = eli; + } + + edge_to_trig[hash] = i2; + } + } + + void UnsetNeighbours( int eli ) + { + for(int edge : Range(3)) + { + auto p0 = trigs[eli][(edge+1)%3]; + auto p1 = trigs[eli][(edge+2)%3]; + if(p1 hash = {p0,p1}; + auto i2 = edge_to_trig.Get({p0,p1}); + + if(i2[0]==eli) + i2[0] = i2[1]; + i2[1] = -1; + + edge_to_trig[hash] = i2; + } + } + + + void AppendTrig( int pi0, int pi1, int pi2 ) + { + DelaunayTrig el; + el[0] = pi0; + el[1] = pi1; + el[2] = pi2; + + el.CalcCenter(mesh); + + trigs.Append(el); + int ti = trigs.Size()-1; + tree->Insert(el.BoundingBox(), ti); + + for(int i : Range(3)) + SetNeighbour(ti, i); + } + + public: + DelaunayMesh( Mesh & mesh_, Box<2> box ) + : mesh(mesh_) + { + Vec<2> vdiag = box.PMax()-box.PMin(); + + double w = vdiag(0); + double h = vdiag(1); + + Point<2> p0 = box.PMin() + Vec<2> ( -3*h, -h); + Point<2> p1 = box.PMin() + Vec<2> (w+3*h, -h); + Point<2> p2 = box.Center() + Vec<2> (0, 1.5*h+0.5*w); + + box.Add( p0 ); + box.Add( p1 ); + box.Add( p2 ); + + tree = make_unique>(box); + + auto pi0 = mesh.AddPoint (P3(p0)); + auto pi1 = mesh.AddPoint (P3(p1)); + auto pi2 = mesh.AddPoint (P3(p2)); + AppendTrig(pi0, pi1, pi2); + } + + void AddPoint( PointIndex pi_new ) + { + Point<2> newp = P2(mesh[pi_new]); + intersecting.SetSize(0); + edges.SetSize(0); + + int definitive_overlapping_trig = -1; + + double minquot{1e20}; + tree->GetFirstIntersecting (newp, newp, [&] (const auto i_trig) + { + const auto trig = trigs[i_trig]; + double rad2 = trig.Radius2(); + double d2 = Dist2 (trig.Center(), newp); + if (d2 >= rad2) return false; + + if (d2 < 0.999 * rad2) + { + definitive_overlapping_trig = i_trig; + return true; + } + + if (definitive_overlapping_trig == -1 || d2 < 0.99*minquot*rad2) + { + minquot = d2/rad2; + definitive_overlapping_trig = i_trig; + } + return false; + }); + + if(definitive_overlapping_trig==-1) + { + cout << "Error in tree - didnt find overlap, check all trigs again" << endl; + for(auto i_trig : trigs.Range()) + { + const auto trig = trigs[i_trig]; + + if(trig[0]==-1) + continue; + + double rad2 = trig.Radius2(); + double d2 = Dist2 (trig.Center(), newp); + + if (d2 < 0.999 * rad2) + { + definitive_overlapping_trig = i_trig; + break; + } + } + } + + BitArray trig_visited(trigs.Size()); + trig_visited.Clear(); + if(definitive_overlapping_trig==-1) + throw Exception("point not in any circle "+ ToString(pi_new)); + + Array trigs_to_visit; + trigs_to_visit.Append(definitive_overlapping_trig); + intersecting.Append(definitive_overlapping_trig); + trig_visited.SetBit(definitive_overlapping_trig); + + while(trigs_to_visit.Size()) + { + int ti = trigs_to_visit.Last(); + trigs_to_visit.DeleteLast(); + + trig_visited.SetBit(ti); + + auto & trig = trigs[ti]; + + for(auto ei : Range(3)) + { + auto nb = GetNeighbour(ti, ei); + if(nb==-1) + continue; + if(trig_visited.Test(nb)) + continue; + + const auto & trig_nb = trigs[nb]; + + + trig_visited.SetBit(nb); + + bool is_intersecting = Dist2(newp, trig_nb.Center()) < trig_nb.Radius2()*(1+1e-12); + + if(!is_intersecting) + { + const Point<2> p0 = P2(mesh[PointIndex (trig[(ei+1)%3])]); + const Point<2> p1 = P2(mesh[PointIndex (trig[(ei+2)%3])]); + const Point<2> p2 = P2(mesh[PointIndex (trig[ei])]); + auto v = p1-p0; + + Vec<2> n = {-v[1], v[0]}; + n /= n.Length(); + + double dist = n * (newp-p1); + double scal = n * (p2 - p1); + if (scal > 0) dist *= -1; + + if (dist > -1e-10) + is_intersecting = true; + } + + if(is_intersecting) + { + trigs_to_visit.Append(nb); + intersecting.Append(nb); + } + } + } + + // find outer edges + for (auto j : intersecting) + { + const DelaunayTrig & trig = trigs[j]; + for (int k = 0; k < 3; k++) + { + int p1 = trig[k]; + int p2 = trig[(k+1)%3]; + INT<2> edge{p1,p2}; + edge.Sort(); + bool found = false; + for (int l = 0; l < edges.Size(); l++) + if (edges[l] == edge) + { + edges.RemoveElement(l); + found = true; + break; + } + if (!found) + edges.Append (edge); + } + } + + for (int j : intersecting) + { + UnsetNeighbours(j); + trigs[j][0] = -1; + trigs[j][1] = -1; + trigs[j][2] = -1; + } + + for (auto edge : edges) + AppendTrig( edge[0], edge[1], pi_new ); + + for (int j : intersecting) + tree->DeleteElement (j); + + static int counter=0; + if(0) + { + Mesh m; + m = mesh; + m.ClearSurfaceElements(); + for (DelaunayTrig & trig : trigs) + { + if (trig[0] < 0) continue; + + Vec<3> n = Cross (mesh[trig[1]]-mesh[trig[0]], + mesh[trig[2]]-mesh[trig[0]]); + if (n(2) < 0) Swap (trig[1], trig[2]); + + Element2d el(trig[0], trig[1], trig[2]); + el.SetIndex (1); + m.AddSurfaceElement (el); + } + m.Save("meshes/mesh_"+ToString(counter++)+".vol.gz"); + } + + } + + Array & GetElements() { return trigs; } + }; ostream & operator<< (ostream & ost, DelaunayTrig trig) @@ -59,20 +369,18 @@ namespace netgen void Meshing2 :: BlockFillLocalH (Mesh & mesh, const MeshingParameters & mp) { - static int timer = NgProfiler::CreateTimer ("Meshing2::BlockFill"); - static int timer1 = NgProfiler::CreateTimer ("Meshing2::BlockFill 1"); - static int timer2 = NgProfiler::CreateTimer ("Meshing2::BlockFill 2"); - static int timer3 = NgProfiler::CreateTimer ("Meshing2::BlockFill 3"); - static int timer4 = NgProfiler::CreateTimer ("Meshing2::BlockFill 4"); - NgProfiler::RegionTimer reg (timer); + static Timer timer("Meshing2::BlockFill"); + static Timer timer1("Meshing2::BlockFill 1"); + static Timer timer2("Meshing2::BlockFill 2"); + static Timer timer3("Meshing2::BlockFill 3"); + static Timer timer4("Meshing2::BlockFill 4"); + RegionTimer reg (timer); - NgProfiler::StartTimer (timer1); + timer1.Start(); double filldist = mp.filldist; - cout << "blockfill local h" << endl; - cout << "rel filldist = " << filldist << endl; - PrintMessage (3, "blockfill local h"); + PrintMessage (6, "blockfill local h"); NgArray > npoints; @@ -95,15 +403,12 @@ namespace netgen } - cout << "bbox = " << bbox << endl; - - // Point<3> mpc = bbox.Center(); bbox.Increase (bbox.Diam()/2); Box<3> meshbox = bbox; - NgProfiler::StopTimer (timer1); - NgProfiler::StartTimer (timer2); + timer1.Stop(); + timer2.Start(); LocalH loch2 (bbox, 1, 2); @@ -147,15 +452,17 @@ namespace netgen } while (changed); - NgProfiler::StopTimer (timer2); - NgProfiler::StartTimer (timer3); + timer2.Stop(); + timer3.Start(); if (debugparam.slowchecks) - (*testout) << "Blockfill with points: " << endl; - *testout << "loch = " << mesh.LocalHFunction() << endl; - - *testout << "npoints = " << endl << npoints << endl; + { + (*testout) << "Blockfill with points: " << endl; + *testout << "loch = " << mesh.LocalHFunction() << endl; + + *testout << "npoints = " << endl << npoints << endl; + } for (int i = 1; i <= npoints.Size(); i++) { @@ -179,8 +486,8 @@ namespace netgen } } - NgProfiler::StopTimer (timer3); - NgProfiler::StartTimer (timer4); + timer3.Stop(); + timer4.Start(); // find outer points @@ -224,7 +531,7 @@ namespace netgen } } - NgProfiler::StopTimer (timer4); + timer4.Stop(); } @@ -232,191 +539,302 @@ namespace netgen void Meshing2 :: Delaunay (Mesh & mesh, int domainnr, const MeshingParameters & mp) { - static int timer = NgProfiler::CreateTimer ("Meshing2::Delaunay - total"); - static int timerstart = NgProfiler::CreateTimer ("Meshing2::Delaunay - start"); - static int timerfinish = NgProfiler::CreateTimer ("Meshing2::Delaunay - finish"); - static int timer1 = NgProfiler::CreateTimer ("Meshing2::Delaunay - incremental"); - static int timer1a = NgProfiler::CreateTimer ("Meshing2::Delaunay - incremental a"); - static int timer1b = NgProfiler::CreateTimer ("Meshing2::Delaunay - incremental b"); - static int timer1c = NgProfiler::CreateTimer ("Meshing2::Delaunay - incremental c"); - static int timer1d = NgProfiler::CreateTimer ("Meshing2::Delaunay - incremental d"); - NgProfiler::RegionTimer reg (timer); + static Timer timer("Meshing2::Delaunay"); + static Timer timer_addpoints("add points"); + RegionTimer reg (timer); + PrintMessage (4, "2D Delaunay meshing"); - - cout << "2D Delaunay meshing (in progress)" << endl; - + auto first_point_blockfill = mesh.Points().Range().Next(); BlockFillLocalH (mesh, mp); - NgProfiler::StartTimer (timerstart); + auto last_point_blockfill = mesh.Points().Range().Next(); - // do the delaunay - - - // face bounding box: - Box<3> bbox (Box<3>::EMPTY_BOX); + // Bounding box for starting trig in delaunay + Box<2> bbox (Box<2>::EMPTY_BOX); for (int i = 0; i < adfront.GetNFL(); i++) { const FrontLine & line = adfront.GetLine(i); - bbox.Add (Point<3> (adfront.GetPoint (line.L()[0]))); - bbox.Add (Point<3> (adfront.GetPoint (line.L()[1]))); + bbox.Add (P2(Point<3> (adfront.GetPoint (line.L()[0])))); + bbox.Add (P2(Point<3> (adfront.GetPoint (line.L()[1])))); } + for (PointIndex pi : Range(first_point_blockfill, last_point_blockfill)) + bbox.Add(P2(mesh[pi])); + for (int i = 0; i < mesh.LockedPoints().Size(); i++) - bbox.Add (mesh.Point (mesh.LockedPoints()[i])); + bbox.Add (P2(mesh.Point (mesh.LockedPoints()[i]))); - cout << "bbox = " << bbox << endl; - - // external point - Vec<3> vdiag = bbox.PMax()-bbox.PMin(); - - auto old_points = mesh.Points().Range(); - DelaunayTrig startel; - startel[0] = mesh.AddPoint (bbox.PMin() + Vec<3> (-8*vdiag(0), -8*vdiag(1), 0)); - startel[1] = mesh.AddPoint (bbox.PMin() + Vec<3> (+8*vdiag(0), -8*vdiag(1), 0)); - startel[2] = mesh.AddPoint (bbox.PMin() + Vec<3> (0, 8*vdiag(1), 0)); - - Box<3> hbox; - hbox.Set (mesh[startel[0]]); - hbox.Add (mesh[startel[1]]); - hbox.Add (mesh[startel[2]]); - Point<3> hp = mesh[startel[0]]; - hp(2) = 1; hbox.Add (hp); - hp(2) = -1; hbox.Add (hp); - BoxTree<3> searchtree(hbox); - - NgArray tempels; - startel.CalcCenter (mesh); - - tempels.Append (startel); - searchtree.Insert(startel.BoundingBox(), 0); - - NgArray closeels; - NgArray intersecting; - NgArray edges; - - - - - // reorder points - NgArray mixed(old_points.Size()); - int prims[] = { 11, 13, 17, 19, 23, 29, 31, 37 }; - int prim; - + Array old_points; + BitArray add_point(mesh.Points().Size()+1); + add_point.Clear(); + for (SegmentIndex si = 0; si < mesh.GetNSeg(); si++) { - int i = 0; - while (old_points.Size() % prims[i] == 0) i++; - prim = prims[i]; + const auto & s = mesh[si]; + if ( s.domin==domainnr || s.domout==domainnr ) + { + add_point.SetBit(s[0]); + add_point.SetBit(s[1]); + } } - for (PointIndex pi : old_points) - mixed[pi] = PointIndex ( (prim * pi) % old_points.Size() + PointIndex::BASE ); + Mesh tempmesh; + tempmesh.AddFaceDescriptor (FaceDescriptor (1, 1, 0, 0)); + tempmesh.AddFaceDescriptor (FaceDescriptor (2, 1, 0, 0)); + tempmesh.AddFaceDescriptor (FaceDescriptor (3, 1, 0, 0)); + + Array compress; + Array icompress(mesh.Points().Size()); + + for(auto pi : mesh.Points().Range()) + if(add_point.Test(pi)) + { + icompress[pi] = tempmesh.AddPoint(mesh[pi]); + compress.Append(pi); + } + + for (PointIndex pi : Range(first_point_blockfill, last_point_blockfill)) + { + icompress[pi] = tempmesh.AddPoint(mesh[pi]); + compress.Append(pi); + } + + // DelaunayMesh adds surrounding trig (don't add the last 3 points to delaunay AGAIN! + auto tempmesh_points = tempmesh.Points().Range(); + + DelaunayMesh dmesh(tempmesh, bbox); + + timer_addpoints.Start(); + +// // reorder points +// NgArray mixed(old_points.Size()); +// int prims[] = { 11, 13, 17, 19, 23, 29, 31, 37 }; +// int prim; +// +// { +// int i = 0; +// while (old_points.Size() % prims[i] == 0) i++; +// prim = prims[i]; +// } +// +// for (PointIndex pi : old_points) +// mixed[pi] = PointIndex ( (prim * pi) % old_points.Size() + PointIndex::BASE ); - NgProfiler::StopTimer (timerstart); - NgProfiler::StartTimer (timer1); + for (auto pi : tempmesh_points) + dmesh.AddPoint(pi); + + timer_addpoints.Stop(); - for (PointIndex i1 : old_points) + for (auto seg : mesh.LineSegments()) + { + if ( seg.domin == domainnr || seg.domout == domainnr ) { - PointIndex i = mixed[i1]; - - NgProfiler::StartTimer (timer1a); - Point<3> newp = mesh[i]; - intersecting.SetSize(0); - edges.SetSize(0); - - searchtree.GetIntersecting (newp, newp, closeels); - // for (int jj = 0; jj < closeels.Size(); jj++) - // for (int j = 0; j < tempels.Size(); j++) - for (int j : closeels) - { - if (tempels[j][0] < 0) continue; - Point<3> c = tempels[j].Center(); - double r2 = tempels[j].Radius2(); - - bool inside = Dist2(mesh[i], c) < r2; - if (inside) intersecting.Append (j); - } - - NgProfiler::StopTimer (timer1a); - NgProfiler::StartTimer (timer1b); - - // find outer edges - for (auto j : intersecting) - { - const DelaunayTrig & trig = tempels[j]; - for (int k = 0; k < 3; k++) - { - int p1 = trig[k]; - int p2 = trig[(k+1)%3]; - INDEX_2 edge(p1,p2); - edge.Sort(); - bool found = false; - for (int l = 0; l < edges.Size(); l++) - if (edges[l] == edge) - { - edges.Delete(l); - found = true; - break; - } - if (!found) edges.Append (edge); - } - } - - NgProfiler::StopTimer (timer1b); - NgProfiler::StartTimer (timer1c); - - /* - for (int j = intersecting.Size()-1; j >= 0; j--) - tempels.Delete (intersecting[j]); - */ - for (int j : intersecting) - { - searchtree.DeleteElement (j); - tempels[j][0] = -1; - tempels[j][1] = -1; - tempels[j][2] = -1; - } - - NgProfiler::StopTimer (timer1c); - NgProfiler::StartTimer (timer1d); - - for (auto edge : edges) - { - DelaunayTrig trig (edge[0], edge[1], i); - trig.CalcCenter (mesh); - tempels.Append (trig); - searchtree.Insert(trig.BoundingBox(), tempels.Size()-1); - } - - NgProfiler::StopTimer (timer1d); + if(seg.domin==domainnr) + seg.domout = 0; + if(seg.domout==domainnr) + seg.domin = 0; + seg[0] = icompress[seg[0]]; + seg[1] = icompress[seg[1]]; + tempmesh.AddSegment(seg); } + } - NgProfiler::StopTimer (timer1); - NgProfiler::StartTimer (timerfinish); + for (auto & trig : dmesh.GetElements()) + { + if (trig[0] < 0) continue; - for (DelaunayTrig & trig : tempels) + Element2d el(trig[0], trig[1], trig[2]); + el.SetIndex (1); + tempmesh.AddSurfaceElement (el); + } + + bool conforming = false; + while(!conforming) + { + conforming = true; + BitArray marked_points(tempmesh.Points().Size()+1); + marked_points = false; + // Check for trigs cutting a boundary edge (non-conforming mesh) + auto point_to_trigs = tempmesh.CreatePoint2SurfaceElementTable( 0 ); + for (auto & seg : tempmesh.LineSegments()) { - if (trig[0] < 0) continue; + int count_adjacent = 0;; + PointIndex pi0 = seg[0]; + PointIndex pi1 = seg[1]; + if(marked_points.Test(pi0)) continue; + if(marked_points.Test(pi1)) continue; - Point<3> c = Center (mesh[trig[0]], mesh[trig[1]], mesh[trig[2]]); - if (!adfront.Inside (Point<2> (c(0),c(1)))) continue; + for(auto sei : point_to_trigs[pi0]) + for( auto i : Range(3)) + if(tempmesh[sei][i] == pi1) + count_adjacent++; - Vec<3> n = Cross (mesh[trig[1]]-mesh[trig[0]], - mesh[trig[2]]-mesh[trig[0]]); - if (n(2) < 0) Swap (trig[1], trig[2]); + if(count_adjacent==2) + continue; - Element2d el(trig[0], trig[1], trig[2]); - el.SetIndex (domainnr); - mesh.AddSurfaceElement (el); + PointIndex pi2; + PointIndex pi3; + ArrayMem cutting_trigs; + for(auto sei : point_to_trigs[pi0]) + { + auto & el = tempmesh[sei]; + pi2 = el[0] == pi0 ? el[1] : el[0]; + pi3 = el[2] == pi0 ? el[1] : el[2]; + double alpha, beta; + auto itype = intersect( P2(tempmesh[pi0]), P2(tempmesh[pi1]), P2(tempmesh[pi2]), P2(tempmesh[pi3]), alpha, beta ); + if(itype == X_INTERSECTION) + { + cutting_trigs.Append(sei); + break; + } + } + if(cutting_trigs.Size()==0) + continue; + for(auto sei : point_to_trigs[pi2]) + { + if(sei==cutting_trigs[0]) + continue; + for(auto i : IntRange(3)) + if(tempmesh[sei][i]==pi3) + cutting_trigs.Append(sei); + } + + // Found two trigs cutting a boundary edge -> perform swap + if(cutting_trigs.Size()==2) + { + conforming = false; + if(marked_points.Test(pi2)) continue; + if(marked_points.Test(pi3)) continue; + + auto & el0 = tempmesh[cutting_trigs[0]]; + auto & el1 = tempmesh[cutting_trigs[1]]; + + pi1 = el1[0]+el1[1]+el1[2] - pi2-pi3; + + if(marked_points.Test(pi1)) continue; + + marked_points.SetBit(pi0); + marked_points.SetBit(pi1); + marked_points.SetBit(pi2); + marked_points.SetBit(pi3); + + el0[0] = pi2; + el0[1] = pi1; + el0[2] = pi0; + + el1[0] = pi3; + el1[1] = pi0; + el1[2] = pi1; + } } + } - for (PointIndex pi : mesh.Points().Range()) - *testout << pi << ": " << mesh[pi].Type() << endl; + auto point_to_trigs = tempmesh.CreatePoint2SurfaceElementTable( 0 ); - NgProfiler::StopTimer (timerfinish); + // Mark edges and trigs as inside or outside, starting with boundary edges + enum POSITION { UNKNOWN, BOUNDARY, INSIDE, OUTSIDE }; + Array trig_pos(tempmesh.SurfaceElements().Size()); + ngcore::ClosedHashTable, POSITION> edge_pos(3*tempmesh.SurfaceElements().Size()); + trig_pos = UNKNOWN; + + for (auto & seg : tempmesh.LineSegments()) + { + ArrayMem els; + INT<2> edge{seg[0], seg[1]}; + edge.Sort(); + edge_pos[edge] = BOUNDARY; + + for(auto sei : point_to_trigs[seg[0]]) + for( auto i : Range(3)) + if(tempmesh[sei][i] == seg[1]) + els.Append(sei); + + for(auto sei : els) + { + auto & el = tempmesh[sei]; + PointIndex pi2 = el[0]+el[1]+el[2] - seg[0] - seg[1]; + bool is_left = ::netgen::Area(P2(tempmesh[seg[0]]), P2(tempmesh[seg[1]]), P2(tempmesh[pi2]))>0.0; + POSITION pos; + + if(is_left == (seg.domin==domainnr)) + pos = INSIDE; + else + pos = OUTSIDE; + + INT<2> e1{seg[0], pi2}; + INT<2> e2{seg[1], pi2}; + e1.Sort(); + e2.Sort(); + if(!edge_pos.Used(e1)) + edge_pos[e1] = pos; + if(!edge_pos.Used(e2)) + edge_pos[e2] = pos; + trig_pos[sei] = pos; + } + } + + // Advance from boundary edges/trigs to all others + bool have_unknown_trigs = true; + while(have_unknown_trigs) + { + have_unknown_trigs = false; + + for (auto sei : Range(tempmesh.SurfaceElements())) + { + auto & el = tempmesh[sei]; + + if(trig_pos[sei] == UNKNOWN) + { + have_unknown_trigs = true; + + // any edge of unkown trig already marked? + for(auto i : IntRange(3)) + { + INT<2> edge{el[(i+1)%3], el[(i+2)%3]}; + edge.Sort(); + if(edge_pos.Used(edge) && edge_pos[edge]!=BOUNDARY) + { + trig_pos[sei] = edge_pos[edge]; + break; + } + } + } + + // if we could mark the trig -> also mark all edges + if(trig_pos[sei] != UNKNOWN) + for(auto i : IntRange(3)) + { + INT<2> edge{el[(i+1)%3], el[(i+2)%3]}; + edge.Sort(); + if(!edge_pos.Used(edge) || edge_pos[edge]==BOUNDARY) + edge_pos[edge] = trig_pos[sei]; + } + } + } + + // add inside trigs to actual mesh + for (auto sei : Range(tempmesh.SurfaceElements())) + { + if(trig_pos[sei] == INSIDE) + { + auto el = tempmesh[sei]; + + Vec<3> n = Cross (tempmesh[el[1]]-tempmesh[el[0]], + tempmesh[el[2]]-tempmesh[el[0]]); + if (n(2) < 0) Swap (el[1], el[2]); + + el[0] = compress[el[0]]; + el[1] = compress[el[1]]; + el[2] = compress[el[2]]; + el.SetIndex(domainnr); + mesh.AddSurfaceElement(el); + } + } + + mesh.Compress(); } } diff --git a/libsrc/meshing/meshtype.hpp b/libsrc/meshing/meshtype.hpp index be4482d6..2f49ad70 100644 --- a/libsrc/meshing/meshtype.hpp +++ b/libsrc/meshing/meshtype.hpp @@ -1263,8 +1263,10 @@ namespace netgen bool uselocalh = true; /// grading for local h double grading = 0.3; - /// use delaunay meshing + /// use delaunay for 3d meshing bool delaunay = true; + /// use delaunay for 2d meshing + bool delaunay2d = false; /// maximal mesh size double maxh = 1e10; /// minimal mesh size diff --git a/libsrc/meshing/python_mesh.hpp b/libsrc/meshing/python_mesh.hpp index 6deab5d2..110c26ee 100644 --- a/libsrc/meshing/python_mesh.hpp +++ b/libsrc/meshing/python_mesh.hpp @@ -48,6 +48,9 @@ filldist: float = 0.1 delaunay: bool = True Use delaunay meshing. +delaunay2d : bool = True + Use delaunay meshing for 2d geometries. + Optimization Parameters ----------------------- @@ -109,6 +112,8 @@ inline void CreateMPfromKwargs(MeshingParameters& mp, py::kwargs kwargs, bool th mp.grading = py::cast(kwargs.attr("pop")("grading")); if(kwargs.contains("delaunay")) mp.delaunay = py::cast(kwargs.attr("pop")("delaunay")); + if(kwargs.contains("delaunay2d")) + mp.delaunay2d = py::cast(kwargs.attr("pop")("delaunay2d")); if(kwargs.contains("maxh")) mp.maxh = py::cast(kwargs.attr("pop")("maxh")); if(kwargs.contains("minh")) From dab18a1c8a96f758e2342e3de993fc2fb85579bf Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Fri, 16 Oct 2020 18:40:04 +0200 Subject: [PATCH 208/384] optimize CalcPartition() and PartitionBoundary() new test results (2d meshing behaviour is changed with this commit) --- libsrc/geom2d/genmesh2d.cpp | 51 +++++++++++------ tests/pytest/results.json | 106 ++++++++++++++++++------------------ 2 files changed, 88 insertions(+), 69 deletions(-) diff --git a/libsrc/geom2d/genmesh2d.cpp b/libsrc/geom2d/genmesh2d.cpp index 6d00f1fe..f94e8854 100644 --- a/libsrc/geom2d/genmesh2d.cpp +++ b/libsrc/geom2d/genmesh2d.cpp @@ -18,29 +18,44 @@ namespace netgen { double fperel, oldf, f; - int n = 10000; - - NgArray > xi(n); - NgArray hi(n); - - for (int i = 0; i < n; i++) + int n = 1; + NgArray > xi; + NgArray hi; + + // do one extra step + int not_fine_enough = 2; + + while(not_fine_enough && n < 10000) + { + not_fine_enough--; + n*=4; + + xi.SetSize(n); + hi.SetSize(n); + + for (int i = 0; i < n; i++) { - xi[i] = spline.GetPoint ( (i+0.5) / n ); - hi[i] = mesh.GetH (Point<3> (xi[i](0), xi[i](1), 0)); + xi[i] = spline.GetPoint ( (i+0.5) / n ); + hi[i] = mesh.GetH (Point<3> (xi[i](0), xi[i](1), 0)); } - // limit slope - double gradh = min(1/elto0,mp.grading); - for (int i = 0; i < n-1; i++) + // limit slope + double gradh = min(1/elto0,mp.grading); + for (int i = 0; i < n-1; i++) { - double hnext = hi[i] + gradh * (xi[i+1]-xi[i]).Length(); - hi[i+1] = min(hi[i+1], hnext); + double hnext = hi[i] + gradh * (xi[i+1]-xi[i]).Length(); + if(hnext > 2*hi[i]) + not_fine_enough = 2; + hi[i+1] = min(hi[i+1], hnext); } - for (int i = n-1; i > 1; i--) + for (int i = n-1; i > 1; i--) { - double hnext = hi[i] + gradh * (xi[i-1]-xi[i]).Length(); - hi[i-1] = min(hi[i-1], hnext); + double hnext = hi[i] + gradh * (xi[i-1]-xi[i]).Length(); + if(hnext > 2*hi[i]) + not_fine_enough = 2; + hi[i-1] = min(hi[i-1], hnext); } + } points.SetSize (0); @@ -227,6 +242,10 @@ namespace netgen mesh2d.RestrictLocalHLine (Point<3>(p1(0),p1(1),0), Point<3>(p2(0),p2(1),0), len/mp.segmentsperedge); + // skip curvature restrictions for straight lines + if(spline.MaxCurvature()==0) + continue; + double hcurve = min (spline.hmax, h/spline.reffak); double hl = GetDomainMaxh (spline.leftdom); if (hl > 0) hcurve = min2 (hcurve, hl); diff --git a/tests/pytest/results.json b/tests/pytest/results.json index b2845af1..3ede7173 100644 --- a/tests/pytest/results.json +++ b/tests/pytest/results.json @@ -1513,8 +1513,8 @@ 0.0, 0.0 ], - "ne1d": 84, - "ne2d": 436, + "ne1d": 70, + "ne2d": 403, "ne3d": 0, "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]", "total_badness": 0.0 @@ -1528,8 +1528,8 @@ 0.0, 0.0 ], - "ne1d": 86, - "ne2d": 476, + "ne1d": 71, + "ne2d": 394, "ne3d": 0, "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]", "total_badness": 0.0 @@ -1543,8 +1543,8 @@ 0.0, 0.0 ], - "ne1d": 86, - "ne2d": 490, + "ne1d": 72, + "ne2d": 395, "ne3d": 0, "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]", "total_badness": 0.0 @@ -1558,8 +1558,8 @@ 0.0, 0.0 ], - "ne1d": 84, - "ne2d": 436, + "ne1d": 70, + "ne2d": 403, "ne3d": 0, "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]", "total_badness": 0.0 @@ -1573,8 +1573,8 @@ 0.0, 0.0 ], - "ne1d": 84, - "ne2d": 460, + "ne1d": 74, + "ne2d": 410, "ne3d": 0, "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]", "total_badness": 0.0 @@ -1588,8 +1588,8 @@ 0.0, 0.0 ], - "ne1d": 88, - "ne2d": 496, + "ne1d": 82, + "ne2d": 442, "ne3d": 0, "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]", "total_badness": 0.0 @@ -2229,18 +2229,18 @@ }, { "angles_tet": [ - 16.884, + 16.888, 145.04 ], "angles_trig": [ - 16.408, + 17.592, 134.95 ], "ne1d": 240, "ne2d": 1830, - "ne3d": 3859, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 6, 25, 68, 162, 284, 407, 508, 515, 505, 411, 383, 323, 208, 54]", - "total_badness": 5750.8446823 + "ne3d": 3886, + "quality_histogram": "[0, 0, 0, 0, 0, 1, 3, 27, 70, 177, 288, 405, 522, 502, 496, 407, 393, 336, 210, 49]", + "total_badness": 5799.4091506 }, { "angles_tet": [ @@ -2270,7 +2270,7 @@ "ne2d": 6864, "ne3d": 33174, "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 2, 2, 52, 185, 571, 1253, 2563, 4038, 5675, 6688, 6259, 4556, 1330]", - "total_badness": 41696.548837 + "total_badness": 41696.548838 }, { "angles_tet": [ @@ -2713,8 +2713,8 @@ 0.0, 0.0 ], - "ne1d": 35, - "ne2d": 121, + "ne1d": 24, + "ne2d": 82, "ne3d": 0, "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]", "total_badness": 0.0 @@ -2728,8 +2728,8 @@ 0.0, 0.0 ], - "ne1d": 30, - "ne2d": 98, + "ne1d": 16, + "ne2d": 44, "ne3d": 0, "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]", "total_badness": 0.0 @@ -2743,8 +2743,8 @@ 0.0, 0.0 ], - "ne1d": 30, - "ne2d": 96, + "ne1d": 11, + "ne2d": 29, "ne3d": 0, "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]", "total_badness": 0.0 @@ -2758,8 +2758,8 @@ 0.0, 0.0 ], - "ne1d": 35, - "ne2d": 121, + "ne1d": 24, + "ne2d": 82, "ne3d": 0, "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]", "total_badness": 0.0 @@ -2773,8 +2773,8 @@ 0.0, 0.0 ], - "ne1d": 44, - "ne2d": 190, + "ne1d": 36, + "ne2d": 146, "ne3d": 0, "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]", "total_badness": 0.0 @@ -2788,8 +2788,8 @@ 0.0, 0.0 ], - "ne1d": 58, - "ne2d": 396, + "ne1d": 22, + "ne2d": 82, "ne3d": 0, "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]", "total_badness": 0.0 @@ -2805,8 +2805,8 @@ 0.0, 0.0 ], - "ne1d": 32, - "ne2d": 158, + "ne1d": 28, + "ne2d": 146, "ne3d": 0, "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]", "total_badness": 0.0 @@ -2820,8 +2820,8 @@ 0.0, 0.0 ], - "ne1d": 32, - "ne2d": 130, + "ne1d": 22, + "ne2d": 134, "ne3d": 0, "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]", "total_badness": 0.0 @@ -2835,8 +2835,8 @@ 0.0, 0.0 ], - "ne1d": 32, - "ne2d": 140, + "ne1d": 28, + "ne2d": 142, "ne3d": 0, "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]", "total_badness": 0.0 @@ -2850,8 +2850,8 @@ 0.0, 0.0 ], - "ne1d": 32, - "ne2d": 158, + "ne1d": 28, + "ne2d": 146, "ne3d": 0, "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]", "total_badness": 0.0 @@ -2865,8 +2865,8 @@ 0.0, 0.0 ], - "ne1d": 45, - "ne2d": 313, + "ne1d": 39, + "ne2d": 290, "ne3d": 0, "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]", "total_badness": 0.0 @@ -2880,8 +2880,8 @@ 0.0, 0.0 ], - "ne1d": 81, - "ne2d": 843, + "ne1d": 79, + "ne2d": 837, "ne3d": 0, "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]", "total_badness": 0.0 @@ -2897,8 +2897,8 @@ 0.0, 0.0 ], - "ne1d": 32, - "ne2d": 134, + "ne1d": 28, + "ne2d": 122, "ne3d": 0, "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]", "total_badness": 0.0 @@ -2912,8 +2912,8 @@ 0.0, 0.0 ], - "ne1d": 32, - "ne2d": 108, + "ne1d": 22, + "ne2d": 110, "ne3d": 0, "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]", "total_badness": 0.0 @@ -2927,7 +2927,7 @@ 0.0, 0.0 ], - "ne1d": 32, + "ne1d": 28, "ne2d": 118, "ne3d": 0, "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]", @@ -2942,8 +2942,8 @@ 0.0, 0.0 ], - "ne1d": 32, - "ne2d": 134, + "ne1d": 28, + "ne2d": 122, "ne3d": 0, "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]", "total_badness": 0.0 @@ -2957,8 +2957,8 @@ 0.0, 0.0 ], - "ne1d": 45, - "ne2d": 253, + "ne1d": 39, + "ne2d": 239, "ne3d": 0, "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]", "total_badness": 0.0 @@ -2972,8 +2972,8 @@ 0.0, 0.0 ], - "ne1d": 81, - "ne2d": 709, + "ne1d": 79, + "ne2d": 705, "ne3d": 0, "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]", "total_badness": 0.0 From 01c1411d6546d9daa01acd145ba779be52712c0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20Sch=C3=B6berl?= Date: Sat, 17 Oct 2020 08:18:06 +0200 Subject: [PATCH 209/384] robust implementation of Polyhedra::VecInSolid2 --- libsrc/csg/polyhedra.cpp | 161 ++++++++++++++++++++++++++++++++++++++- libsrc/csg/polyhedra.hpp | 49 +++++++----- 2 files changed, 188 insertions(+), 22 deletions(-) diff --git a/libsrc/csg/polyhedra.cpp b/libsrc/csg/polyhedra.cpp index ae9e53bd..ce35e108 100644 --- a/libsrc/csg/polyhedra.cpp +++ b/libsrc/csg/polyhedra.cpp @@ -355,7 +355,7 @@ namespace netgen const Vec<3> & v, double eps) const { - return VecInSolidOld (p, v, eps); + return VecInSolidNew (p, v, eps); /* auto oldval = VecInSolidOld (p, v, eps); auto newval = VecInSolidNew (p, v, eps); @@ -441,7 +441,8 @@ namespace netgen */ - + // #define OLDVECINSOLID2 +#ifdef OLDVECINSOLID2 INSOLID_TYPE Polyhedra :: VecInSolid2 (const Point<3> & p, const Vec<3> & v1, const Vec<3> & v2, @@ -510,6 +511,162 @@ namespace netgen +#else + + + // check how many faces a ray starting in p+alpha*v+alpha^2/2 v2 intersects: + // if p + alpha v is in plane, use v2 + INSOLID_TYPE Polyhedra :: VecInSolid2 (const Point<3> & p, + const Vec<3> & v, + const Vec<3> & v2, + double eps) const + { + if (!poly_bbox.IsIn (p, eps)) + return IS_OUTSIDE; + + // random (?) direction: + Vec<3> n(-0.424621, 0.1543, 0.89212238); + + int cnt = 0; + for (auto & face : faces) + { + Vec<3> v0 = p - points[face.pnums[0]]; + double lamn = face.nn * v0; + + if (fabs(lamn) < eps) // point is in plane of face + { + double lam1 = face.w1 * v0; + double lam2 = face.w2 * v0; + double lam3 = 1-lam1-lam2; + + if (lam1 >= -eps_base1 && lam2 >= -eps_base1 && lam3 >= -eps_base1) + { // point is close to trianlge, perturbe by alpha*v + double dlamn = face.nn*v; + + if (fabs(dlamn) < 1e-8) // vec also in plane + { + double dlam1 = face.w1 * v; + double dlam2 = face.w2 * v; + double dlam3 = -dlam1-dlam2; + + bool in1 = lam1 > eps_base1 || dlam1 > -eps_base1; + bool in2 = lam2 > eps_base1 || dlam2 > -eps_base1; + bool in3 = lam3 > eps_base1 || dlam3 > -eps_base1; + + // and the same thing for v2 + if (in1 && in2 && in3) + { + double ddlamn = face.nn*v2; + + if (fabs(ddlamn) < 1e-8) // vec2 also in plane + { + double ddlam1 = face.w1 * v2; + double ddlam2 = face.w2 * v2; + double ddlam3 = -ddlam1-ddlam2; + + bool ddin1 = lam1 > eps_base1 || dlam1 > eps_base1 || ddlam1 > -eps_base1; + bool ddin2 = lam2 > eps_base1 || dlam2 > eps_base1 || ddlam2 > -eps_base1; + bool ddin3 = lam3 > eps_base1 || dlam3 > eps_base1 || ddlam3 > -eps_base1; + if (ddin1 && ddin2 && ddin3) + return DOES_INTERSECT; + } + else // vec2 out of plane + { + double ddlamn = -(face.n * v2) / (face.n * n); + if (ddlamn < 0) continue; // ray goes not in direction of face + + Vec<3> drs = v; // + dlamn * n; but dlamn==0 + Vec<3> ddrs = v2 + ddlamn * n; + + double dlam1 = face.w1 * drs; + double dlam2 = face.w2 * drs; + double dlam3 = -dlam1-dlam2; + + double ddlam1 = face.w1 * ddrs; + double ddlam2 = face.w2 * ddrs; + double ddlam3 = -ddlam1-ddlam2; + + bool ddin1 = lam1 > eps_base1 || dlam1 > eps_base1 || ddlam1 > -eps_base1; + bool ddin2 = lam2 > eps_base1 || dlam2 > eps_base1 || ddlam2 > -eps_base1; + bool ddin3 = lam3 > eps_base1 || dlam3 > eps_base1 || ddlam3 > -eps_base1; + + if (ddin1 && ddin2 && ddin3) + cnt++; + } + } + } + else // vec out of plane + { + double dlamn = -(face.n * v) / (face.n * n); + if (dlamn < 0) continue; // ray goes not in direction of face + + Vec<3> drs = v + dlamn * n; + + double dlam1 = face.w1 * drs; + double dlam2 = face.w2 * drs; + double dlam3 = -dlam1-dlam2; + + bool in1 = lam1 > eps_base1 || dlam1 > -eps_base1; + bool in2 = lam2 > eps_base1 || dlam2 > -eps_base1; + bool in3 = lam3 > eps_base1 || dlam3 > -eps_base1; + + if (in1 && in2 && in3) + cnt++; + + } + } + } + else + { + double lamn = -(face.n * v0) / (face.n * n); + + if (lamn < 0) continue; // ray goes not in direction of face + + Vec<3> rs = v0 + lamn * n; + + double lam1 = face.w1 * rs; + double lam2 = face.w2 * rs; + double lam3 = 1-lam1-lam2; + if (lam1 >= 0 && lam2 >= 0 && lam3 >= 0) + cnt++; + } + } + + return (cnt % 2) ? IS_INSIDE : IS_OUTSIDE; + } +#endif + + + + + + + + INSOLID_TYPE Polyhedra :: VecInSolid3 (const Point<3> & p, + const Vec<3> & v1, + const Vec<3> & v2, + double eps) const + { + return VecInSolid2 (p, v1, v2, eps); + } + + INSOLID_TYPE Polyhedra :: VecInSolid4 (const Point<3> & p, + const Vec<3> & v, + const Vec<3> & v2, + const Vec<3> & m, + double eps) const + { + auto res = VecInSolid2 (p, v, v2, eps); + + if (res == DOES_INTERSECT) // following edge second order, let m decide + return VecInSolid2 (p, v, m, eps); + + return res; + } + + + + void Polyhedra :: GetTangentialVecSurfaceIndices2 (const Point<3> & p, const Vec<3> & v1, const Vec<3> & v2, NgArray & surfind, double eps) const { diff --git a/libsrc/csg/polyhedra.hpp b/libsrc/csg/polyhedra.hpp index 720786e4..4ba183d3 100644 --- a/libsrc/csg/polyhedra.hpp +++ b/libsrc/csg/polyhedra.hpp @@ -48,54 +48,63 @@ namespace netgen public: Polyhedra (); - virtual ~Polyhedra (); + virtual ~Polyhedra () override; static Primitive * CreateDefault (); - virtual INSOLID_TYPE BoxInSolid (const BoxSphere<3> & box) const; + virtual INSOLID_TYPE BoxInSolid (const BoxSphere<3> & box) const override; virtual INSOLID_TYPE PointInSolid (const Point<3> & p, - double eps) const; + double eps) const override; virtual INSOLID_TYPE VecInSolidNew (const Point<3> & p, const Vec<3> & v, double eps, bool printing = false) const; virtual INSOLID_TYPE VecInSolidOld (const Point<3> & p, const Vec<3> & v, double eps) const; + virtual INSOLID_TYPE VecInSolid (const Point<3> & p, const Vec<3> & v, - double eps) const; + double eps) const override; - - - // checks if lim s->0 lim t->0 p + t(v1 + s v2) in solid virtual INSOLID_TYPE VecInSolid2 (const Point<3> & p, const Vec<3> & v1, const Vec<3> & v2, - double eps) const; + double eps) const override; + + virtual INSOLID_TYPE VecInSolid3 (const Point<3> & p, + const Vec<3> & v1, + const Vec<3> & v2, + double eps) const override; + virtual INSOLID_TYPE VecInSolid4 (const Point<3> & p, + const Vec<3> & v, + const Vec<3> & v2, + const Vec<3> & m, + double eps) const override; + virtual void GetTangentialSurfaceIndices (const Point<3> & p, - NgArray & surfind, double eps) const; + NgArray & surfind, double eps) const override; virtual void GetTangentialVecSurfaceIndices2 (const Point<3> & p, const Vec<3> & v1, const Vec<3> & v2, - NgArray & surfind, double eps) const; + NgArray & surfind, double eps) const override; - virtual void CalcSpecialPoints (NgArray > & pts) const; + virtual void CalcSpecialPoints (NgArray > & pts) const override; virtual void AnalyzeSpecialPoint (const Point<3> & pt, - NgArray > & specpts) const; - virtual Vec<3> SpecialPointTangentialVector (const Point<3> & p, int s1, int s2) const; + NgArray > & specpts) const override; + virtual Vec<3> SpecialPointTangentialVector (const Point<3> & p, int s1, int s2) const override; - virtual int GetNSurfaces() const + virtual int GetNSurfaces() const override { return planes.Size(); } - virtual Surface & GetSurface (int i) + virtual Surface & GetSurface (int i) override { return *planes[i]; } - virtual const Surface & GetSurface (int i) const + virtual const Surface & GetSurface (int i) const override { return *planes[i]; } - virtual void GetPrimitiveData (const char *& classname, NgArray & coeffs) const; - virtual void SetPrimitiveData (NgArray & coeffs); + virtual void GetPrimitiveData (const char *& classname, NgArray & coeffs) const override; + virtual void SetPrimitiveData (NgArray & coeffs) override; - virtual void Reduce (const BoxSphere<3> & box); - virtual void UnReduce (); + virtual void Reduce (const BoxSphere<3> & box) override; + virtual void UnReduce () override; int AddPoint (const Point<3> & p); int AddFace (int pi1, int pi2, int pi3, int inputnum); From decb6c6e904b63884a93fa9841b5f75e2bdfc050 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20Sch=C3=B6berl?= Date: Sat, 17 Oct 2020 13:01:07 +0200 Subject: [PATCH 210/384] use VecInSolid2 in SpecialPoint analysis, VecInSolid2 return also does_intersect --- libsrc/csg/polyhedra.cpp | 2 +- libsrc/csg/solid.cpp | 44 +++++++++++++++++++++++++++++++++++++++- libsrc/csg/solid.hpp | 5 ++++- libsrc/csg/specpoin.cpp | 39 ++++++++++++++++++++++++++++------- libsrc/csg/surface.cpp | 9 ++++++++ 5 files changed, 89 insertions(+), 10 deletions(-) diff --git a/libsrc/csg/polyhedra.cpp b/libsrc/csg/polyhedra.cpp index ce35e108..7db4f94c 100644 --- a/libsrc/csg/polyhedra.cpp +++ b/libsrc/csg/polyhedra.cpp @@ -540,7 +540,7 @@ namespace netgen double lam3 = 1-lam1-lam2; if (lam1 >= -eps_base1 && lam2 >= -eps_base1 && lam3 >= -eps_base1) - { // point is close to trianlge, perturbe by alpha*v + { // point is close to trianlge, perturbe by alpha*v double dlamn = face.nn*v; if (fabs(dlamn) < 1e-8) // vec also in plane diff --git a/libsrc/csg/solid.cpp b/libsrc/csg/solid.cpp index 58ed069e..70156c35 100644 --- a/libsrc/csg/solid.cpp +++ b/libsrc/csg/solid.cpp @@ -285,6 +285,7 @@ namespace netgen } + /* bool Solid::VectorIn2 (const Point<3> & p, const Vec<3> & v1, const Vec<3> & v2, double eps) const { @@ -317,10 +318,51 @@ namespace netgen } return 0; } + */ + bool Solid::VectorIn2 (const Point<3> & p, const Vec<3> & v1, + const Vec<3> & v2, double eps) const + { + switch (op) + { + case TERM: case TERM_REF: + { + auto res = prim->VecInSolid2 (p, v1, v2, eps); + return res != IS_OUTSIDE; + } + case SECTION: + return s1->VectorIn2 (p, v1, v2, eps) && s2->VectorIn2 (p, v1, v2, eps); + case UNION: + return s1->VectorIn2 (p, v1, v2, eps) || s2->VectorIn2 (p, v1, v2, eps); + case SUB: + return !s1->VectorStrictIn2 (p, v1, v2, eps); + case ROOT: + return s1->VectorIn2 (p, v1, v2, eps); + } + // return 0; + } - + bool Solid :: VectorStrictIn2 (const Point<3> & p, const Vec<3> & v1, const Vec<3> & v2, + double eps) const + { + switch (op) + { + case TERM: case TERM_REF: + { + auto res = prim->VecInSolid2 (p, v1, v2, eps); + return (res == IS_INSIDE); + } + case SECTION: + return s1->VectorStrictIn2 (p, v1, v2, eps) && s2->VectorStrictIn2 (p, v1, v2, eps); + case UNION: + return s1->VectorStrictIn2 (p, v1, v2, eps) || s2->VectorStrictIn2 (p, v1, v2, eps); + case SUB: + return !s1->VectorIn2 (p, v1, v2, eps); + case ROOT: + return s1->VectorStrictIn2 (p, v1, v2, eps); + } + } void Solid :: Print (ostream & str) const diff --git a/libsrc/csg/solid.hpp b/libsrc/csg/solid.hpp index 5f3d6688..d3364203 100644 --- a/libsrc/csg/solid.hpp +++ b/libsrc/csg/solid.hpp @@ -109,9 +109,12 @@ namespace netgen bool VectorIn2 (const Point<3> & p, const Vec<3> & v1, const Vec<3> & v2, double eps) const; + /* bool VectorIn2Rec (const Point<3> & p, const Vec<3> & v1, const Vec<3> & v2, double eps) const; - + */ + bool VectorStrictIn2 (const Point<3> & p, const Vec<3> & v1, const Vec<3> & v2, + double eps) const; /// compute localization in point p unique_ptr TangentialSolid (const Point<3> & p, NgArray & surfids, double eps) const; diff --git a/libsrc/csg/specpoin.cpp b/libsrc/csg/specpoin.cpp index 99c33377..c69a7239 100644 --- a/libsrc/csg/specpoin.cpp +++ b/libsrc/csg/specpoin.cpp @@ -2076,16 +2076,43 @@ namespace netgen continue; Vec<3> s = Cross (normalvecs[m], t); + Vec<3> t2a = t + 0.01 *s; Vec<3> t2b = t - 0.01 *s; - - bool isface = + + bool isfaceold = (locsol->VectorIn (p, t2a, 1e-6*geomsize) && !locsol->VectorStrictIn (p, t2a, 1e-6*geomsize)) || (locsol->VectorIn (p, t2b, 1e-6*geomsize) && !locsol->VectorStrictIn (p, t2b, 1e-6*geomsize)); - + + bool isfacenew = + (locsol->VectorIn2 (p, t, s, 1e-6*geomsize) && !locsol->VectorStrictIn2 (p, t, s, 1e-6*geomsize)) || + (locsol->VectorIn2 (p, t, -s, 1e-6*geomsize) && !locsol->VectorStrictIn2 (p, t, -s, 1e-6*geomsize)); + + bool isface = isfacenew; + + if (isfaceold != isfacenew) + { + *testout << "different, p = " << p << ", t = " << t << ", s = " << s << endl; + *testout << "tlo = " << si << endl; + *testout << "isface, old = " << isface << ", isfacenew = " << isfacenew << endl; + + *testout << "t2a = " << t2a << endl; + *testout << "vecin(p,t2a) = " << locsol->VectorIn (p, t2a, 1e-6*geomsize) << endl; + *testout << "vecstrictin(p,t2a) = " << locsol->VectorStrictIn (p, t2a, 1e-6*geomsize) << endl; + *testout << "vectorin2 = " << locsol->VectorIn2 (p, t, s, 1e-6*geomsize) << endl; + *testout << "vectorstrictin2 = " << locsol->VectorStrictIn2 (p, t, s, 1e-6*geomsize) << endl; + + *testout << "t2b = " << t2b << endl; + *testout << "vecin(p,t2b) = " << locsol->VectorIn (p, t2b, 1e-6*geomsize) << endl; + *testout << "vecstrictin(p,t2b) = " << locsol->VectorStrictIn (p, t2b, 1e-6*geomsize) << endl; + *testout << "vectorin2- = " << locsol->VectorIn2 (p, t, -s, 1e-6*geomsize) << endl; + *testout << "vectorstrictin2- = " << locsol->VectorStrictIn2 (p, t, -s, 1e-6*geomsize) << endl; + } + + /* bool isface = (locsol->VectorIn (p, t2a) && @@ -2095,10 +2122,8 @@ namespace netgen !locsol->VectorStrictIn (p, t2b)); */ - if (isface) - { - cnts++; - } + if (isface) + cnts++; } if (cnts < 2) isedge = 0; } diff --git a/libsrc/csg/surface.cpp b/libsrc/csg/surface.cpp index 8efe1f7a..cb6ab48b 100644 --- a/libsrc/csg/surface.cpp +++ b/libsrc/csg/surface.cpp @@ -427,11 +427,20 @@ VecInSolid2 (const Point<3> & p, if (hv1 >= eps) return IS_OUTSIDE; + double hv2 = v2 * hv; + if (hv2 <= -eps) + return IS_INSIDE; + if (hv2 >= eps) + return IS_OUTSIDE; + return DOES_INTERSECT; + + /* double hv2 = v2 * hv; if (hv2 <= 0) return IS_INSIDE; else return IS_OUTSIDE; + */ } From ad69a9d5a50a4d8be186bc561ce944b679dd2253 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20Sch=C3=B6berl?= Date: Sat, 17 Oct 2020 15:23:53 +0200 Subject: [PATCH 211/384] modernization SpecialPointCalculation --- libsrc/csg/solid.cpp | 119 ++++++++++++++++++++++ libsrc/csg/solid.hpp | 8 ++ libsrc/csg/specpoin.cpp | 211 +++++++++++++--------------------------- 3 files changed, 193 insertions(+), 145 deletions(-) diff --git a/libsrc/csg/solid.cpp b/libsrc/csg/solid.cpp index 70156c35..22d22e80 100644 --- a/libsrc/csg/solid.cpp +++ b/libsrc/csg/solid.cpp @@ -193,6 +193,125 @@ namespace netgen + INSOLID_TYPE Solid :: + PointInSolid (const Point<3> & p, double eps) const + { + switch (op) + { + case TERM: case TERM_REF: + return prim->PointInSolid (p, eps); + case SECTION: + { + auto res1 = s1->PointInSolid (p, eps); + auto res2 = s2->PointInSolid (p, eps); + if (res1 == IS_INSIDE && res2 == IS_INSIDE) return IS_INSIDE; + if (res1 == IS_OUTSIDE || res2 == IS_OUTSIDE) return IS_OUTSIDE; + return DOES_INTERSECT; + } + case UNION: + { + auto res1 = s1->PointInSolid (p, eps); + auto res2 = s2->PointInSolid (p, eps); + if (res1 == IS_INSIDE || res2 == IS_INSIDE) return IS_INSIDE; + if (res1 == IS_OUTSIDE && res2 == IS_OUTSIDE) return IS_OUTSIDE; + return DOES_INTERSECT; + } + case SUB: + { + auto res1 = s1->PointInSolid (p, eps); + switch (res1) + { + case IS_INSIDE: return IS_OUTSIDE; + case IS_OUTSIDE: return IS_INSIDE; + default: return DOES_INTERSECT; + } + } + case ROOT: + return s1->PointInSolid (p, eps); + } + } + + + INSOLID_TYPE Solid :: + VecInSolid (const Point<3> & p, const Vec<3> & v, double eps) const + { + switch (op) + { + case TERM: case TERM_REF: + return prim->VecInSolid (p, v, eps); + case SECTION: + { + auto res1 = s1->VecInSolid (p, v, eps); + auto res2 = s2->VecInSolid (p, v, eps); + if (res1 == IS_INSIDE && res2 == IS_INSIDE) return IS_INSIDE; + if (res1 == IS_OUTSIDE || res2 == IS_OUTSIDE) return IS_OUTSIDE; + return DOES_INTERSECT; + } + case UNION: + { + auto res1 = s1->VecInSolid (p, v, eps); + auto res2 = s2->VecInSolid (p, v, eps); + if (res1 == IS_INSIDE || res2 == IS_INSIDE) return IS_INSIDE; + if (res1 == IS_OUTSIDE && res2 == IS_OUTSIDE) return IS_OUTSIDE; + return DOES_INTERSECT; + } + case SUB: + { + auto res1 = s1->VecInSolid (p, v, eps); + switch (res1) + { + case IS_INSIDE: return IS_OUTSIDE; + case IS_OUTSIDE: return IS_INSIDE; + default: return DOES_INTERSECT; + } + } + case ROOT: + return s1->VecInSolid (p, v, eps); + } + } + + // checks if lim s->0 lim t->0 p + t(v1 + s v2) in solid + INSOLID_TYPE Solid :: + VecInSolid2 (const Point<3> & p, const Vec<3> & v1, + const Vec<3> & v2, double eps) const + { + switch (op) + { + case TERM: case TERM_REF: + return prim->VecInSolid2 (p, v1, v2, eps); + case SECTION: + { + auto res1 = s1->VecInSolid2 (p, v1, v2, eps); + auto res2 = s2->VecInSolid2 (p, v1, v2, eps); + if (res1 == IS_INSIDE && res2 == IS_INSIDE) return IS_INSIDE; + if (res1 == IS_OUTSIDE || res2 == IS_OUTSIDE) return IS_OUTSIDE; + return DOES_INTERSECT; + } + case UNION: + { + auto res1 = s1->VecInSolid2 (p, v1, v2, eps); + auto res2 = s2->VecInSolid2 (p, v1, v2, eps); + if (res1 == IS_INSIDE || res2 == IS_INSIDE) return IS_INSIDE; + if (res1 == IS_OUTSIDE && res2 == IS_OUTSIDE) return IS_OUTSIDE; + return DOES_INTERSECT; + } + case SUB: + { + auto res1 = s1->VecInSolid2 (p, v1, v2, eps); + switch (res1) + { + case IS_INSIDE: return IS_OUTSIDE; + case IS_OUTSIDE: return IS_INSIDE; + default: return DOES_INTERSECT; + } + } + case ROOT: + return s1->VecInSolid2 (p, v1, v2, eps); + } + } + + + bool Solid :: IsIn (const Point<3> & p, double eps) const { diff --git a/libsrc/csg/solid.hpp b/libsrc/csg/solid.hpp index d3364203..4d18d3df 100644 --- a/libsrc/csg/solid.hpp +++ b/libsrc/csg/solid.hpp @@ -102,6 +102,14 @@ namespace netgen // geometric tests + INSOLID_TYPE PointInSolid (const Point<3> & p, double eps) const; + INSOLID_TYPE VecInSolid (const Point<3> & p, const Vec<3> & v, double eps) const; + + // checks if lim s->0 lim t->0 p + t(v1 + s v2) in solid + INSOLID_TYPE VecInSolid2 (const Point<3> & p, const Vec<3> & v1, + const Vec<3> & v2, double eps) const; + + bool IsIn (const Point<3> & p, double eps = 1e-6) const; bool IsStrictIn (const Point<3> & p, double eps = 1e-6) const; bool VectorIn (const Point<3> & p, const Vec<3> & v, double eps = 1e-6) const; diff --git a/libsrc/csg/specpoin.cpp b/libsrc/csg/specpoin.cpp index c69a7239..439f2a24 100644 --- a/libsrc/csg/specpoin.cpp +++ b/libsrc/csg/specpoin.cpp @@ -286,36 +286,30 @@ namespace netgen dynamic_cast (geometry->GetSurface(locsurf[k3])), pts); - for (int j = 0; j < pts.Size(); j++) - if (Dist (pts[j], box.Center()) < box.Diam()/2) + for (auto pnt : pts) + if (Dist (pnt, box.Center()) < box.Diam()/2) { - // Solid * tansol; - auto tansol = sol -> TangentialSolid (pts[j], surfids, 1e-9*size); - - if(!tansol) - continue; - - bool ok1 = false, ok2 = false, ok3 = false; - int rep1 = geometry->GetSurfaceClassRepresentant(locsurf[k1]); - int rep2 = geometry->GetSurfaceClassRepresentant(locsurf[k2]); - int rep3 = geometry->GetSurfaceClassRepresentant(locsurf[k3]); - for(int jj=0; jjGetSurfaceClassRepresentant(surfids[jj]); - if(actrep == rep1) ok1 = true; - if(actrep == rep2) ok2 = true; - if(actrep == rep3) ok3 = true; - } - - - if (tansol && ok1 && ok2 && ok3) - // if (sol -> IsIn (pts[j], 1e-6*size) && !sol->IsStrictIn (pts[j], 1e-6*size)) - { - if (AddPoint (pts[j], layer)) - (*testout) << "cross point found, 1: " << pts[j] << endl; - } - // delete tansol; - } + auto tansol = sol -> TangentialSolid (pnt, surfids, 1e-9*size); + if (tansol) + { + bool ok1 = false, ok2 = false, ok3 = false; + int rep1 = geometry->GetSurfaceClassRepresentant(locsurf[k1]); + int rep2 = geometry->GetSurfaceClassRepresentant(locsurf[k2]); + int rep3 = geometry->GetSurfaceClassRepresentant(locsurf[k3]); + + for (auto surfid : surfids) + { + int actrep = geometry->GetSurfaceClassRepresentant(surfid); + if (actrep == rep1) ok1 = true; + if (actrep == rep2) ok2 = true; + if (actrep == rep3) ok3 = true; + } + + if (ok1 && ok2 && ok3) + if (AddPoint (pnt, layer)) + (*testout) << "cross point found, 1: " << pnt << endl; + } + } } @@ -330,39 +324,30 @@ namespace netgen qsurf, pts); //(*testout) << "checking pot. crosspoints: " << pts << endl; - for (int j = 0; j < pts.Size(); j++) - if (Dist (pts[j], box.Center()) < box.Diam()/2) + for (auto pnt : pts) + if (Dist (pnt, box.Center()) < box.Diam()/2) { - // Solid * tansol; - auto tansol = sol -> TangentialSolid (pts[j], surfids, 1e-9*size); - - if(!tansol) - continue; - - bool ok1 = false, ok2 = false, ok3 = true;//false; - int rep1 = geometry->GetSurfaceClassRepresentant(locsurf[k1]); - int rep2 = geometry->GetSurfaceClassRepresentant(locsurf[k2]); - //int rep3 = geometry->GetSurfaceClassRepresentant(quadi); - for(int jj=0; jjGetSurfaceClassRepresentant(surfids[jj]); - if(actrep == rep1) ok1 = true; - if(actrep == rep2) ok2 = true; - //if(actrep == rep3) ok3 = true; - } - - - if (tansol && ok1 && ok2 && ok3) - //if (sol -> IsIn (pts[j], 1e-6*size) && !sol->IsStrictIn (pts[j], 1e-6*size) ) - { - if (AddPoint (pts[j], layer)) - (*testout) << "cross point found, 2: " << pts[j] << endl; - } - // delete tansol; + auto tansol = sol -> TangentialSolid (pnt, surfids, 1e-9*size); + if (tansol) + { + bool ok1 = false, ok2 = false, ok3 = true;//false; + int rep1 = geometry->GetSurfaceClassRepresentant(locsurf[k1]); + int rep2 = geometry->GetSurfaceClassRepresentant(locsurf[k2]); + + for (auto surfid : surfids) + { + int actrep = geometry->GetSurfaceClassRepresentant(surfid); + if (actrep == rep1) ok1 = true; + if (actrep == rep2) ok2 = true; + } + + if (ok1 && ok2 && ok3) + if (AddPoint (pnt, layer)) + (*testout) << "cross point found, 2: " << pnt << endl; + } } } - for (int k1 = 0; k1 < numprim; k1++) if (k1 != quadi) { @@ -372,15 +357,10 @@ namespace netgen for (int j = 0; j < pts.Size(); j++) if (Dist (pts[j], box.Center()) < box.Diam()/2) { - // Solid * tansol; auto tansol = sol -> TangentialSolid (pts[j], surfids, 1e-9*size); if (tansol) - // sol -> IsIn (pts[j], 1e-6*size) && !sol->IsStrictIn (pts[j], 1e-6*size) ) - { - if (AddPoint (pts[j], layer)) - (*testout) << "extremal point found, 1: " << pts[j] << endl; - } - // delete tansol; + if (AddPoint (pts[j], layer)) + (*testout) << "extremal point found, 1: " << pts[j] << endl; } } } @@ -395,8 +375,6 @@ namespace netgen NgArray > pts; NgArray surfids; - - for (int k1 = 0; k1 < numprim; k1++) for (int k2 = 0; k2 < k1; k2++) for (int k3 = 0; k3 < k2; k3++) @@ -409,16 +387,14 @@ namespace netgen for (int j = 0; j < pts.Size(); j++) if (Dist (pts[j], box.Center()) < box.Diam()/2) { - // Solid * tansol; auto tansol = sol -> TangentialSolid (pts[j], surfids, 1e-9*size); - - if(!tansol) - continue; + if (!tansol) continue; bool ok1 = false, ok2 = false, ok3 = false; int rep1 = geometry->GetSurfaceClassRepresentant(locsurf[k1]); int rep2 = geometry->GetSurfaceClassRepresentant(locsurf[k2]); int rep3 = geometry->GetSurfaceClassRepresentant(locsurf[k3]); + for(int jj=0; jjGetSurfaceClassRepresentant(surfids[jj]); @@ -427,14 +403,9 @@ namespace netgen if(actrep == rep3) ok3 = true; } - - if (tansol && ok1 && ok2 && ok3) - // if (sol -> IsIn (pts[j], 1e-6*size) && !sol->IsStrictIn (pts[j], 1e-6*size)) - { - if (AddPoint (pts[j], layer)) - (*testout) << "cross point found, 1: " << pts[j] << endl; - } - // delete tansol; + if (ok1 && ok2 && ok3) + if (AddPoint (pts[j], layer)) + (*testout) << "cross point found, 1: " << pts[j] << endl; } } @@ -449,30 +420,23 @@ namespace netgen for (int j = 0; j < pts.Size(); j++) if (Dist (pts[j], box.Center()) < box.Diam()/2) { - // Solid * tansol; auto tansol = sol -> TangentialSolid (pts[j], surfids, 1e-9*size); if (tansol) - // sol -> IsIn (pts[j], 1e-6*size) && !sol->IsStrictIn (pts[j], 1e-6*size) ) - { - if (AddPoint (pts[j], layer)) - (*testout) << "extremal point found, spheres: " << pts[j] << endl; - } - // delete tansol; + if (AddPoint (pts[j], layer)) + (*testout) << "extremal point found, spheres: " << pts[j] << endl; } } return; } - if (numprim == 2 && - (typeid(*geometry->GetSurface(locsurf[0])) == typeid(RevolutionFace&)) && - (typeid(*geometry->GetSurface(locsurf[1])) == typeid(RevolutionFace&))) + + auto rev0 = dynamic_cast (geometry->GetSurface(locsurf[0])); + auto rev1 = dynamic_cast (geometry->GetSurface(locsurf[1])); + if (numprim == 2 && rev0 && rev1) { NgArray> pts; - bool check = - ComputeExtremalPoints (static_cast (geometry->GetSurface(locsurf[0])), - static_cast (geometry->GetSurface(locsurf[1])), - pts); + bool check = ComputeExtremalPoints (rev0, rev1, pts); if (check) { // int cnt_inbox = 0; @@ -489,7 +453,6 @@ namespace netgen */ } } - } // end if (numprim <= check_crosspoint) @@ -521,7 +484,6 @@ namespace netgen (*testout) << "k1,2,3 = " << k1 << "," << k2 << "," << k3 << ", nc = " << nc << ", deg = " << deg << endl; #endif - if (!nc && !deg) decision = 0; if (nc) surecrossp = 1; } @@ -1829,10 +1791,8 @@ namespace netgen continue; - // Solid * locsol; auto locsol = sol -> TangentialSolid (p, surfind, ideps*geomsize); - rep_surfind.SetSize (surfind.Size()); int num_indep_surfs = 0; @@ -1859,10 +1819,10 @@ namespace netgen if (surf) { // locsol -> GetSurfaceIndices (surfind); - bool hassurf = 0; + bool hassurf = false; for (int m = 0; m < surfind.Size(); m++) if (ageometry.GetSurface(surfind[m]) == surf) - hassurf = 1; + hassurf = true; if (!hassurf) continue; @@ -1955,19 +1915,14 @@ namespace netgen CalcInverse (mat, inv); t2 = inv * rhs; - // t2 = StableSolve (mat, rhs); #ifdef DEVELOP *testout << "t = " << t << ", t2 = " << t2 << endl; #endif - - - /* ageometry.GetIndependentSurfaceIndices (locsol, p, t, surfind2); */ - // Solid * locsol2; auto locsol2 = locsol -> TangentialSolid3 (p, t, t2, surfind2, ideps*geomsize); if (!locsol2) continue; @@ -2009,13 +1964,10 @@ namespace netgen Vec<3> nv = ageometry.GetSurface(surfind2[l]) -> GetNormalVector(p); - Vec<3> m1 = Cross (t, nv); Vec<3> m2 = -m1; bool isface1 = 0, isface2 = 0; - // Solid * locsol3; - // locsol2 -> TangentialSolid2 (p, m1, locsol3, surfind3, 1e-9*geomsize); auto locsol3 = locsol -> TangentialEdgeSolid (p, t, t2, m1, surfind3, ideps*geomsize); #ifdef DEVELOP @@ -2025,7 +1977,6 @@ namespace netgen if (surfind3.Contains(surfind2[l])) isface1 = 1; - // delete locsol3; // locsol2 -> TangentialSolid2 (p, m2, locsol3, surfind3, 1e-9*geomsize); locsol3 = locsol -> TangentialEdgeSolid (p, t, t2, m2, surfind3, ideps*geomsize); @@ -2038,7 +1989,6 @@ namespace netgen if (surfind3.Contains(surfind2[l])) isface2 = 1; - // delete locsol3; if (isface1 != isface2) cnt_tang_faces++; @@ -2051,7 +2001,6 @@ namespace netgen if (cnt_tang_faces < 1) ok = false; - // delete locsol2; if (!ok) continue; } @@ -2088,8 +2037,12 @@ namespace netgen !locsol->VectorStrictIn (p, t2b, 1e-6*geomsize)); bool isfacenew = + locsol -> VecInSolid2(p, t, s, 1e-6*geomsize) == DOES_INTERSECT || + locsol -> VecInSolid2(p, t, -s, 1e-6*geomsize) == DOES_INTERSECT; + /* (locsol->VectorIn2 (p, t, s, 1e-6*geomsize) && !locsol->VectorStrictIn2 (p, t, s, 1e-6*geomsize)) || (locsol->VectorIn2 (p, t, -s, 1e-6*geomsize) && !locsol->VectorStrictIn2 (p, t, -s, 1e-6*geomsize)); + */ bool isface = isfacenew; @@ -2182,46 +2135,15 @@ namespace netgen } } - - // delete locsol; } } - /* - NgBitArray testuncond (specpoints.Size()); - testuncond.Clear(); - for(int i = 0; i same; - same.Append(i); - - for(int j = i+1; j Date: Sat, 17 Oct 2020 17:08:58 +0200 Subject: [PATCH 212/384] cleanup solid checks --- libsrc/csg/solid.cpp | 111 ++++++++++------------------------------ libsrc/csg/solid.hpp | 20 ++++++++ libsrc/csg/specpoin.cpp | 2 +- libsrc/csg/surface.hpp | 2 - 4 files changed, 48 insertions(+), 87 deletions(-) diff --git a/libsrc/csg/solid.cpp b/libsrc/csg/solid.cpp index 22d22e80..52bd6321 100644 --- a/libsrc/csg/solid.cpp +++ b/libsrc/csg/solid.cpp @@ -6,21 +6,6 @@ namespace netgen { - //using namespace netgen; - - - /* - SolidIterator :: SolidIterator () - { - ; - } - - SolidIterator :: ~SolidIterator () - { - ; - } - */ - // int Solid :: cntnames = 0; @@ -201,31 +186,11 @@ namespace netgen case TERM: case TERM_REF: return prim->PointInSolid (p, eps); case SECTION: - { - auto res1 = s1->PointInSolid (p, eps); - auto res2 = s2->PointInSolid (p, eps); - if (res1 == IS_INSIDE && res2 == IS_INSIDE) return IS_INSIDE; - if (res1 == IS_OUTSIDE || res2 == IS_OUTSIDE) return IS_OUTSIDE; - return DOES_INTERSECT; - } + return Intersection (s1->PointInSolid (p, eps), s2->PointInSolid (p, eps)); case UNION: - { - auto res1 = s1->PointInSolid (p, eps); - auto res2 = s2->PointInSolid (p, eps); - if (res1 == IS_INSIDE || res2 == IS_INSIDE) return IS_INSIDE; - if (res1 == IS_OUTSIDE && res2 == IS_OUTSIDE) return IS_OUTSIDE; - return DOES_INTERSECT; - } + return Union (s1->PointInSolid (p, eps), s2->PointInSolid (p, eps)); case SUB: - { - auto res1 = s1->PointInSolid (p, eps); - switch (res1) - { - case IS_INSIDE: return IS_OUTSIDE; - case IS_OUTSIDE: return IS_INSIDE; - default: return DOES_INTERSECT; - } - } + return Complement (s1->PointInSolid (p, eps)); case ROOT: return s1->PointInSolid (p, eps); } @@ -240,31 +205,11 @@ namespace netgen case TERM: case TERM_REF: return prim->VecInSolid (p, v, eps); case SECTION: - { - auto res1 = s1->VecInSolid (p, v, eps); - auto res2 = s2->VecInSolid (p, v, eps); - if (res1 == IS_INSIDE && res2 == IS_INSIDE) return IS_INSIDE; - if (res1 == IS_OUTSIDE || res2 == IS_OUTSIDE) return IS_OUTSIDE; - return DOES_INTERSECT; - } + return Intersection (s1->VecInSolid (p, v, eps), s2->VecInSolid (p, v, eps)); case UNION: - { - auto res1 = s1->VecInSolid (p, v, eps); - auto res2 = s2->VecInSolid (p, v, eps); - if (res1 == IS_INSIDE || res2 == IS_INSIDE) return IS_INSIDE; - if (res1 == IS_OUTSIDE && res2 == IS_OUTSIDE) return IS_OUTSIDE; - return DOES_INTERSECT; - } + return Union (s1->VecInSolid (p, v, eps), s2->VecInSolid (p, v, eps)); case SUB: - { - auto res1 = s1->VecInSolid (p, v, eps); - switch (res1) - { - case IS_INSIDE: return IS_OUTSIDE; - case IS_OUTSIDE: return IS_INSIDE; - default: return DOES_INTERSECT; - } - } + return Complement (s1->VecInSolid (p, v, eps)); case ROOT: return s1->VecInSolid (p, v, eps); } @@ -280,31 +225,11 @@ namespace netgen case TERM: case TERM_REF: return prim->VecInSolid2 (p, v1, v2, eps); case SECTION: - { - auto res1 = s1->VecInSolid2 (p, v1, v2, eps); - auto res2 = s2->VecInSolid2 (p, v1, v2, eps); - if (res1 == IS_INSIDE && res2 == IS_INSIDE) return IS_INSIDE; - if (res1 == IS_OUTSIDE || res2 == IS_OUTSIDE) return IS_OUTSIDE; - return DOES_INTERSECT; - } + return Intersection (s1->VecInSolid2 (p, v1, v2, eps), s2->VecInSolid2 (p, v1, v2, eps)); case UNION: - { - auto res1 = s1->VecInSolid2 (p, v1, v2, eps); - auto res2 = s2->VecInSolid2 (p, v1, v2, eps); - if (res1 == IS_INSIDE || res2 == IS_INSIDE) return IS_INSIDE; - if (res1 == IS_OUTSIDE && res2 == IS_OUTSIDE) return IS_OUTSIDE; - return DOES_INTERSECT; - } + return Union (s1->VecInSolid2 (p, v1, v2, eps), s2->VecInSolid2 (p, v1, v2, eps)); case SUB: - { - auto res1 = s1->VecInSolid2 (p, v1, v2, eps); - switch (res1) - { - case IS_INSIDE: return IS_OUTSIDE; - case IS_OUTSIDE: return IS_INSIDE; - default: return DOES_INTERSECT; - } - } + return Complement (s1->VecInSolid2 (p, v1, v2, eps)); case ROOT: return s1->VecInSolid2 (p, v1, v2, eps); } @@ -315,6 +240,8 @@ namespace netgen bool Solid :: IsIn (const Point<3> & p, double eps) const { + return PointInSolid (p,eps) != IS_OUTSIDE; + /* switch (op) { case TERM: case TERM_REF: @@ -332,10 +259,13 @@ namespace netgen return s1->IsIn (p, eps); } return 0; + */ } bool Solid :: IsStrictIn (const Point<3> & p, double eps) const { + return PointInSolid (p,eps) == IS_INSIDE; + /* switch (op) { case TERM: case TERM_REF: @@ -353,11 +283,14 @@ namespace netgen return s1->IsStrictIn (p, eps); } return 0; + */ } bool Solid :: VectorIn (const Point<3> & p, const Vec<3> & v, double eps) const { + return VecInSolid (p,v,eps) != IS_OUTSIDE; + /* Vec<3> hv; switch (op) { @@ -376,11 +309,14 @@ namespace netgen return s1->VectorIn(p, v, eps); } return 0; + */ } bool Solid :: VectorStrictIn (const Point<3> & p, const Vec<3> & v, double eps) const { + return VecInSolid (p,v,eps) == IS_INSIDE; + /* Vec<3> hv; switch (op) { @@ -401,6 +337,7 @@ namespace netgen return s1->VectorStrictIn(p, v, eps); } return 0; + */ } @@ -443,6 +380,8 @@ namespace netgen bool Solid::VectorIn2 (const Point<3> & p, const Vec<3> & v1, const Vec<3> & v2, double eps) const { + return VecInSolid2 (p,v1,v2,eps) != IS_OUTSIDE; + /* switch (op) { case TERM: case TERM_REF: @@ -460,11 +399,14 @@ namespace netgen return s1->VectorIn2 (p, v1, v2, eps); } // return 0; + */ } bool Solid :: VectorStrictIn2 (const Point<3> & p, const Vec<3> & v1, const Vec<3> & v2, double eps) const { + return VecInSolid2 (p,v1,v2,eps) == IS_INSIDE; + /* switch (op) { case TERM: case TERM_REF: @@ -481,6 +423,7 @@ namespace netgen case ROOT: return s1->VectorStrictIn2 (p, v1, v2, eps); } + */ } diff --git a/libsrc/csg/solid.hpp b/libsrc/csg/solid.hpp index 4d18d3df..b3c10807 100644 --- a/libsrc/csg/solid.hpp +++ b/libsrc/csg/solid.hpp @@ -33,6 +33,26 @@ namespace netgen }; + inline INSOLID_TYPE Intersection (INSOLID_TYPE ina, INSOLID_TYPE inb) + { + if (ina == IS_INSIDE && inb == IS_INSIDE) return IS_INSIDE; + if (ina == IS_OUTSIDE || inb == IS_OUTSIDE) return IS_OUTSIDE; + return DOES_INTERSECT; + } + + inline INSOLID_TYPE Union (INSOLID_TYPE ina, INSOLID_TYPE inb) + { + if (ina == IS_INSIDE || inb == IS_INSIDE) return IS_INSIDE; + if (ina == IS_OUTSIDE && inb == IS_OUTSIDE) return IS_OUTSIDE; + return DOES_INTERSECT; + } + + inline INSOLID_TYPE Complement (INSOLID_TYPE in) + { + if (in == IS_INSIDE) return IS_OUTSIDE; + if (in == IS_OUTSIDE) return IS_INSIDE; + return DOES_INTERSECT; + } class Solid { diff --git a/libsrc/csg/specpoin.cpp b/libsrc/csg/specpoin.cpp index 439f2a24..d5a38cf9 100644 --- a/libsrc/csg/specpoin.cpp +++ b/libsrc/csg/specpoin.cpp @@ -2148,7 +2148,7 @@ namespace netgen for (int i = 0; i < specpoints.Size(); i++) if (specpoints[i].unconditional) - uncond.Set (specpoint2point[i]); + uncond.SetBit (specpoint2point[i]); for (int i = 0; i < specpoints.Size(); i++) specpoints[i].unconditional = uncond.Test (specpoint2point[i]); diff --git a/libsrc/csg/surface.hpp b/libsrc/csg/surface.hpp index d2b52cbe..f09d8c51 100644 --- a/libsrc/csg/surface.hpp +++ b/libsrc/csg/surface.hpp @@ -213,8 +213,6 @@ namespace netgen INSOLID_TYPE; - - class DummySurface : public Surface { virtual double CalcFunctionValue (const Point<3> & /* point */) const From b3d757ccd1a87d27eeb41648f64403c5193e5a04 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Sat, 17 Oct 2020 17:25:18 +0200 Subject: [PATCH 213/384] update pybind11 to 2.6.0rc3 --- external_dependencies/pybind11 | 2 +- libsrc/core/python_ngcore.hpp | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/external_dependencies/pybind11 b/external_dependencies/pybind11 index deb3cb23..c16da993 160000 --- a/external_dependencies/pybind11 +++ b/external_dependencies/pybind11 @@ -1 +1 @@ -Subproject commit deb3cb238a9f299d7c57f810165e90a1b14b3e6f +Subproject commit c16da993094988141101ac4d96a9b2c92f9ac714 diff --git a/libsrc/core/python_ngcore.hpp b/libsrc/core/python_ngcore.hpp index b26b8481..912395b2 100644 --- a/libsrc/core/python_ngcore.hpp +++ b/libsrc/core/python_ngcore.hpp @@ -16,8 +16,8 @@ namespace py = pybind11; //////////////////////////////////////////////////////////////////////////////// // automatic conversion of python list to Array<> -NAMESPACE_BEGIN(PYBIND11_NAMESPACE) -NAMESPACE_BEGIN(detail) +PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) +PYBIND11_NAMESPACE_BEGIN(detail) template struct ngcore_list_caster { using value_conv = make_caster; @@ -60,8 +60,8 @@ template struct type_caster> : ngcore_list_caster, Type> { }; -NAMESPACE_END(detail) -NAMESPACE_END(PYBIND11_NAMESPACE) +PYBIND11_NAMESPACE_END(detail) +PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE) //////////////////////////////////////////////////////////////////////////////// namespace ngcore From 2b5d00b259c3a56db1746cf4b45d74a0f52e895c Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Mon, 19 Oct 2020 10:41:44 +0200 Subject: [PATCH 214/384] csg2d - add points as 0d-elements to mesh --- libsrc/geom2d/csg2d.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsrc/geom2d/csg2d.cpp b/libsrc/geom2d/csg2d.cpp index 4fa163d9..880d8547 100644 --- a/libsrc/geom2d/csg2d.cpp +++ b/libsrc/geom2d/csg2d.cpp @@ -1856,7 +1856,7 @@ shared_ptr CSG2d :: GenerateSplineGeometry() { // not found -> insert to tree netgen::GeomPoint<2> gp(p); - gp.name = ""; + gp.name = "default"; geo->geompoints.Append(gp); ptree.Insert(p,p,geo->geompoints.Size()-1); } From 9d5661fdc5fe0bc93648afb105740e49ce7f57f8 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Mon, 19 Oct 2020 13:19:25 +0200 Subject: [PATCH 215/384] Fix maxh issue for splines --- libsrc/geom2d/genmesh2d.cpp | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/libsrc/geom2d/genmesh2d.cpp b/libsrc/geom2d/genmesh2d.cpp index bcade21d..088c4f59 100644 --- a/libsrc/geom2d/genmesh2d.cpp +++ b/libsrc/geom2d/genmesh2d.cpp @@ -242,23 +242,28 @@ namespace netgen mesh2d.RestrictLocalHLine (Point<3>(p1(0),p1(1),0), Point<3>(p2(0),p2(1),0), len/mp.segmentsperedge); - // skip curvature restrictions for straight lines - if(spline.MaxCurvature()==0) - continue; - double hcurve = min (spline.hmax, h/spline.reffak); double hl = GetDomainMaxh (spline.leftdom); if (hl > 0) hcurve = min2 (hcurve, hl); double hr = GetDomainMaxh (spline.rightdom); if (hr > 0) hcurve = min2 (hcurve, hr); - int np = 1000; - for (double t = 0.5/np; t < 1; t += 1.0/np) - { - Point<2> x = spline.GetPoint(t); - double hc = 1.0/mp.curvaturesafety / (1e-99+spline.CalcCurvature (t)); - mesh2d.RestrictLocalH (Point<3> (x(0), x(1), 0), min2(hc, hcurve)); - } + // skip curvature restrictions for straight lines + if(spline.MaxCurvature()==0) + { + mesh2d.RestrictLocalHLine (Point<3>(p1(0),p1(1),0), + Point<3>(p2(0),p2(1),0), hcurve); + } + else + { + int np = 1000; + for (double t = 0.5/np; t < 1; t += 1.0/np) + { + Point<2> x = spline.GetPoint(t); + double hc = 1.0/mp.curvaturesafety / (1e-99+spline.CalcCurvature (t)); + mesh2d.RestrictLocalH (Point<3> (x(0), x(1), 0), min2(hc, hcurve)); + } + } } for (auto mspnt : mp.meshsize_points) From 00b49592320059ae1bb08ec2234b8c8fe39d5c01 Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Mon, 19 Oct 2020 14:06:35 +0200 Subject: [PATCH 216/384] remove "normal vectors degenerated" output --- libsrc/csg/specpoin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsrc/csg/specpoin.cpp b/libsrc/csg/specpoin.cpp index d5a38cf9..39066362 100644 --- a/libsrc/csg/specpoin.cpp +++ b/libsrc/csg/specpoin.cpp @@ -1870,7 +1870,7 @@ namespace netgen if (Abs2 (t) < 1e-16) { - cerr << "normal vectors degenerated" << endl; + // cerr << "normal vectors degenerated" << endl; continue; } From 397ef354a336feae2b142dba99d363a186c1edda Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Mon, 19 Oct 2020 15:18:42 +0200 Subject: [PATCH 217/384] test with range checks enabled --- .gitlab-ci.yml | 2 ++ tests/build_debug.sh | 1 + tests/build_mpi.sh | 6 +++++- tests/build_ngsolve.sh | 1 + 4 files changed, 9 insertions(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index a862660a..0b4c60bc 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -55,6 +55,7 @@ build_win: cmake %SRC_DIR% -G Ninja -DCMAKE_INSTALL_PREFIX=%INSTALL_DIR% + -DCHECK_RANGE=ON -DUSE_CGNS=ON -DUSE_OCC=ON -DOCC_LIBRARY=C:/install_opencascade_7.4.0_static/win64/vc14/lib/TKernel.lib @@ -238,6 +239,7 @@ build_mac: cmake $SRC_DIR -DCMAKE_INSTALL_PREFIX=$CMAKE_INSTALL_PREFIX -DCMAKE_BUILD_TYPE=Release + -DCHECK_RANGE=ON -DUSE_NATIVE_ARCH=OFF -DUSE_CCACHE=ON -DENABLE_UNIT_TESTS=ON diff --git a/tests/build_debug.sh b/tests/build_debug.sh index 349722d8..e779b381 100755 --- a/tests/build_debug.sh +++ b/tests/build_debug.sh @@ -6,6 +6,7 @@ cmake \ -DBUILD_TYPE=DEBUG \ -DENABLE_UNIT_TESTS=ON \ -DUSE_OCC=ON \ + -DCHECK_RANGE=ON \ -DUSE_CGNS=ON \ ../../src/netgen make -j12 diff --git a/tests/build_mpi.sh b/tests/build_mpi.sh index 190423ac..0e26af94 100644 --- a/tests/build_mpi.sh +++ b/tests/build_mpi.sh @@ -1,6 +1,10 @@ cd mkdir -p build/netgen cd build/netgen -cmake ../../src/netgen -DUSE_CCACHE=ON -DUSE_MPI=ON -DENABLE_UNIT_TESTS=ON +cmake ../../src/netgen \ + -DCHECK_RANGE=ON \ + -DUSE_CCACHE=ON \ + -DUSE_MPI=ON \ + -DENABLE_UNIT_TESTS=ON make -j12 make install diff --git a/tests/build_ngsolve.sh b/tests/build_ngsolve.sh index a25a628a..d452d2da 100755 --- a/tests/build_ngsolve.sh +++ b/tests/build_ngsolve.sh @@ -3,6 +3,7 @@ git clone https://github.com/NGSolve/ngsolve.git mkdir -p ~/build/ngsolve cd ~/build/ngsolve cmake \ + -DCHECK_RANGE=ON \ -DUSE_MKL=ON \ -DUSE_CCACHE=ON \ -DNETGEN_DIR=/opt/netgen \ From ce3f3429d4668024d0d062b76bd39b69436e26de Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Mon, 19 Oct 2020 15:27:36 +0200 Subject: [PATCH 218/384] fix range check exception in tutorials --- libsrc/csg/specpoin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsrc/csg/specpoin.cpp b/libsrc/csg/specpoin.cpp index 39066362..33b098f5 100644 --- a/libsrc/csg/specpoin.cpp +++ b/libsrc/csg/specpoin.cpp @@ -432,7 +432,7 @@ namespace netgen auto rev0 = dynamic_cast (geometry->GetSurface(locsurf[0])); - auto rev1 = dynamic_cast (geometry->GetSurface(locsurf[1])); + auto rev1 = locsurf.Size() > 1 ? dynamic_cast (geometry->GetSurface(locsurf[1])) : nullptr; if (numprim == 2 && rev0 && rev1) { NgArray> pts; From b28a1bc5cc67c4cc7e77ad6df77834e8b3187210 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Mon, 19 Oct 2020 15:45:16 +0200 Subject: [PATCH 219/384] update test results --- tests/pytest/results.json | 116 +++++++++++++++++++------------------- 1 file changed, 58 insertions(+), 58 deletions(-) diff --git a/tests/pytest/results.json b/tests/pytest/results.json index 3ede7173..04cb980d 100644 --- a/tests/pytest/results.json +++ b/tests/pytest/results.json @@ -1513,8 +1513,8 @@ 0.0, 0.0 ], - "ne1d": 70, - "ne2d": 403, + "ne1d": 81, + "ne2d": 442, "ne3d": 0, "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]", "total_badness": 0.0 @@ -1528,8 +1528,8 @@ 0.0, 0.0 ], - "ne1d": 71, - "ne2d": 394, + "ne1d": 86, + "ne2d": 464, "ne3d": 0, "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]", "total_badness": 0.0 @@ -1543,8 +1543,8 @@ 0.0, 0.0 ], - "ne1d": 72, - "ne2d": 395, + "ne1d": 86, + "ne2d": 466, "ne3d": 0, "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]", "total_badness": 0.0 @@ -1558,23 +1558,8 @@ 0.0, 0.0 ], - "ne1d": 70, - "ne2d": 403, - "ne3d": 0, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]", - "total_badness": 0.0 - }, - { - "angles_tet": [ - 0.0, - 0.0 - ], - "angles_trig": [ - 0.0, - 0.0 - ], - "ne1d": 74, - "ne2d": 410, + "ne1d": 81, + "ne2d": 442, "ne3d": 0, "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]", "total_badness": 0.0 @@ -1589,7 +1574,22 @@ 0.0 ], "ne1d": 82, - "ne2d": 442, + "ne2d": 441, + "ne3d": 0, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]", + "total_badness": 0.0 + }, + { + "angles_tet": [ + 0.0, + 0.0 + ], + "angles_trig": [ + 0.0, + 0.0 + ], + "ne1d": 86, + "ne2d": 472, "ne3d": 0, "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]", "total_badness": 0.0 @@ -2713,8 +2713,8 @@ 0.0, 0.0 ], - "ne1d": 24, - "ne2d": 82, + "ne1d": 31, + "ne2d": 99, "ne3d": 0, "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]", "total_badness": 0.0 @@ -2728,8 +2728,8 @@ 0.0, 0.0 ], - "ne1d": 16, - "ne2d": 44, + "ne1d": 27, + "ne2d": 75, "ne3d": 0, "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]", "total_badness": 0.0 @@ -2743,8 +2743,8 @@ 0.0, 0.0 ], - "ne1d": 11, - "ne2d": 29, + "ne1d": 25, + "ne2d": 85, "ne3d": 0, "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]", "total_badness": 0.0 @@ -2758,8 +2758,8 @@ 0.0, 0.0 ], - "ne1d": 24, - "ne2d": 82, + "ne1d": 31, + "ne2d": 99, "ne3d": 0, "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]", "total_badness": 0.0 @@ -2773,8 +2773,8 @@ 0.0, 0.0 ], - "ne1d": 36, - "ne2d": 146, + "ne1d": 41, + "ne2d": 177, "ne3d": 0, "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]", "total_badness": 0.0 @@ -2788,8 +2788,8 @@ 0.0, 0.0 ], - "ne1d": 22, - "ne2d": 82, + "ne1d": 30, + "ne2d": 108, "ne3d": 0, "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]", "total_badness": 0.0 @@ -2805,8 +2805,8 @@ 0.0, 0.0 ], - "ne1d": 28, - "ne2d": 146, + "ne1d": 32, + "ne2d": 148, "ne3d": 0, "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]", "total_badness": 0.0 @@ -2820,8 +2820,8 @@ 0.0, 0.0 ], - "ne1d": 22, - "ne2d": 134, + "ne1d": 32, + "ne2d": 140, "ne3d": 0, "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]", "total_badness": 0.0 @@ -2835,8 +2835,8 @@ 0.0, 0.0 ], - "ne1d": 28, - "ne2d": 142, + "ne1d": 32, + "ne2d": 148, "ne3d": 0, "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]", "total_badness": 0.0 @@ -2850,8 +2850,8 @@ 0.0, 0.0 ], - "ne1d": 28, - "ne2d": 146, + "ne1d": 32, + "ne2d": 148, "ne3d": 0, "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]", "total_badness": 0.0 @@ -2865,8 +2865,8 @@ 0.0, 0.0 ], - "ne1d": 39, - "ne2d": 290, + "ne1d": 43, + "ne2d": 300, "ne3d": 0, "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]", "total_badness": 0.0 @@ -2881,7 +2881,7 @@ 0.0 ], "ne1d": 79, - "ne2d": 837, + "ne2d": 821, "ne3d": 0, "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]", "total_badness": 0.0 @@ -2897,8 +2897,8 @@ 0.0, 0.0 ], - "ne1d": 28, - "ne2d": 122, + "ne1d": 32, + "ne2d": 124, "ne3d": 0, "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]", "total_badness": 0.0 @@ -2912,8 +2912,8 @@ 0.0, 0.0 ], - "ne1d": 22, - "ne2d": 110, + "ne1d": 32, + "ne2d": 116, "ne3d": 0, "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]", "total_badness": 0.0 @@ -2927,8 +2927,8 @@ 0.0, 0.0 ], - "ne1d": 28, - "ne2d": 118, + "ne1d": 32, + "ne2d": 124, "ne3d": 0, "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]", "total_badness": 0.0 @@ -2942,8 +2942,8 @@ 0.0, 0.0 ], - "ne1d": 28, - "ne2d": 122, + "ne1d": 32, + "ne2d": 124, "ne3d": 0, "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]", "total_badness": 0.0 @@ -2957,8 +2957,8 @@ 0.0, 0.0 ], - "ne1d": 39, - "ne2d": 239, + "ne1d": 43, + "ne2d": 249, "ne3d": 0, "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]", "total_badness": 0.0 @@ -2973,7 +2973,7 @@ 0.0 ], "ne1d": 79, - "ne2d": 705, + "ne2d": 687, "ne3d": 0, "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]", "total_badness": 0.0 From 39be1fd3c92579a85794606dd6b164e2bb47d6bd Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Mon, 19 Oct 2020 16:32:42 +0200 Subject: [PATCH 220/384] add PointInfo for csg2d for maxh and name in points --- libsrc/geom2d/csg2d.cpp | 13 ++++++++++--- libsrc/geom2d/csg2d.hpp | 24 +++++++++++++++++++++++- libsrc/geom2d/python_geom2d.cpp | 16 +++++++++++----- python/geom2d.py | 2 +- 4 files changed, 45 insertions(+), 10 deletions(-) diff --git a/libsrc/geom2d/csg2d.cpp b/libsrc/geom2d/csg2d.cpp index 880d8547..da236920 100644 --- a/libsrc/geom2d/csg2d.cpp +++ b/libsrc/geom2d/csg2d.cpp @@ -1171,8 +1171,10 @@ next_P: ; // add duplicate vertices to P and Q auto V_P = I_P->Insert(*I_P, I_P->lam); V_P->spline = I_P->spline; + V_P->pinfo = I_P->pinfo; auto V_Q = I_Q->Insert(*I_Q, I_Q->lam); V_Q->spline = I_Q->spline; + V_Q->pinfo = I_Q->pinfo; // link vertices correctly if (sP*sQ > 0) { // same local orientation @@ -1580,7 +1582,7 @@ bool Loop :: IsInside( Point<2> r ) const } -Solid2d :: Solid2d(const Array, EdgeInfo>> & points, string name_, string bc) +Solid2d :: Solid2d(const Array, EdgeInfo, PointInfo>> & points, string name_, string bc) : name(name_) { Loop l; @@ -1590,6 +1592,8 @@ Solid2d :: Solid2d(const Array, EdgeInfo>> & points, strin l.Append(*point, true); if(auto edge_info = std::get_if(&v)) l.first->prev->info.Assign( *edge_info ); + if(auto point_info = std::get_if(&v)) + l.first->pinfo.Assign(*point_info); } for(auto v : l.Vertices(ALL)) @@ -1849,17 +1853,20 @@ shared_ptr CSG2d :: GenerateSplineGeometry() }; t_points.Start(); - auto insertPoint = [&](Point<2> p ) + auto insertPoint = [&](const Vertex& p ) { int pi = getPoint(p); if(pi==-1) { // not found -> insert to tree netgen::GeomPoint<2> gp(p); - gp.name = "default"; geo->geompoints.Append(gp); + pi = geo->geompoints.Size()-1; ptree.Insert(p,p,geo->geompoints.Size()-1); } + geo->geompoints[pi].hmax = min2(geo->geompoints[pi].hmax, p.pinfo.maxh); + if(p.pinfo.name != POINT_NAME_DEFAULT) + geo->geompoints[pi].name = p.pinfo.name; }; for(auto & s : solids) diff --git a/libsrc/geom2d/csg2d.hpp b/libsrc/geom2d/csg2d.hpp index fbb4b8b0..118060f8 100644 --- a/libsrc/geom2d/csg2d.hpp +++ b/libsrc/geom2d/csg2d.hpp @@ -65,6 +65,7 @@ enum IteratorType }; inline constexpr const double MAXH_DEFAULT{1e99}; +inline const string POINT_NAME_DEFAULT{""}; inline const string BC_DEFAULT{""}; inline const string MAT_DEFAULT{""}; @@ -93,6 +94,24 @@ struct EdgeInfo } }; +struct PointInfo +{ + double maxh = MAXH_DEFAULT; + string name = POINT_NAME_DEFAULT; + PointInfo() = default; + PointInfo(const PointInfo& other) = default; + PointInfo(double amaxh) : maxh(amaxh) {} + PointInfo(string aname) : name(aname) {} + PointInfo(double amaxh, string aname) : maxh(amaxh), name(aname) {} + + void Assign(const PointInfo& other) + { + maxh = min(maxh, other.maxh); + if(other.name != POINT_NAME_DEFAULT) + name = other.name; + } +}; + struct Vertex : Point<2> { Vertex (Point<2> p) : Point<2>(p) {} @@ -100,6 +119,7 @@ struct Vertex : Point<2> { spline = v.spline; info = v.info; + pinfo = v.pinfo; is_source = true; } @@ -117,6 +137,7 @@ struct Vertex : Point<2> // In case the edge this - next is curved, store the spline information here optional spline = nullopt; EdgeInfo info; + PointInfo pinfo; DLL_HEADER Vertex * Insert(Point<2> p, double lam = -1.0); @@ -455,6 +476,7 @@ struct Loop { auto & vnew = Append( static_cast>(v), true ); vnew.info = v.info; + vnew.pinfo = v.pinfo; if(v.spline) vnew.spline = *v.spline; if(bbox) @@ -628,7 +650,7 @@ struct Solid2d Solid2d() = default; Solid2d(string name_) : name(name_) {} - DLL_HEADER Solid2d(const Array, EdgeInfo>> & points, string name_=MAT_DEFAULT, string bc_=BC_DEFAULT); + DLL_HEADER Solid2d(const Array, EdgeInfo, PointInfo>> & points, string name_=MAT_DEFAULT, string bc_=BC_DEFAULT); Solid2d(Solid2d && other) = default; Solid2d(const Solid2d & other) = default; diff --git a/libsrc/geom2d/python_geom2d.cpp b/libsrc/geom2d/python_geom2d.cpp index b5a07a1f..b8f5a871 100644 --- a/libsrc/geom2d/python_geom2d.cpp +++ b/libsrc/geom2d/python_geom2d.cpp @@ -399,7 +399,7 @@ DLL_HEADER void ExportGeom2d(py::module &m) py::class_(m, "Solid2d") .def(py::init<>()) - .def(py::init, EdgeInfo>>, std::string, std::string>(), py::arg("points"), py::arg("mat")=MAT_DEFAULT, py::arg("bc")=BC_DEFAULT) + .def(py::init, EdgeInfo, PointInfo>>, std::string, std::string>(), py::arg("points"), py::arg("mat")=MAT_DEFAULT, py::arg("bc")=BC_DEFAULT) .def(py::self+py::self) .def(py::self-py::self) @@ -431,10 +431,10 @@ DLL_HEADER void ExportGeom2d(py::module &m) { using P = Point<2>; return { { - p0, bottom ? *bottom : bc, - P{p1[0],p0[1]}, right ? *right : bc, - p1, top ? *top : bc, - P{p0[0],p1[1]}, left ? *left : bc, + p0, EdgeInfo{bottom ? *bottom : bc}, + P{p1[0],p0[1]}, EdgeInfo {right ? *right : bc}, + p1, EdgeInfo {top ? *top : bc}, + P{p0[0],p1[1]}, EdgeInfo {left ? *left : bc}, }, mat}; }, "pmin"_a, "pmax"_a, "mat"_a=MAT_DEFAULT, "bc"_a=BC_DEFAULT, @@ -475,6 +475,12 @@ DLL_HEADER void ExportGeom2d(py::module &m) .def(py::init(), py::arg("bc")) .def(py::init>, double, string>(), py::arg("control_point")=nullopt, py::arg("maxh")=MAXH_DEFAULT, py::arg("bc")=BC_DEFAULT) ; + py::class_(m, "PointInfo") + .def(py::init<>()) + .def(py::init(), "maxh"_a) + .def(py::init(), "name"_a) + .def(py::init(), "maxh"_a, "name"_a) + ; } PYBIND11_MODULE(libgeom2d, m) { diff --git a/python/geom2d.py b/python/geom2d.py index c4cdf3c7..886bfb60 100644 --- a/python/geom2d.py +++ b/python/geom2d.py @@ -1,4 +1,4 @@ -from .libngpy._geom2d import SplineGeometry, Solid2d, CSG2d, Rectangle, Circle, EdgeInfo +from .libngpy._geom2d import SplineGeometry, Solid2d, CSG2d, Rectangle, Circle, EdgeInfo, PointInfo from .meshing import meshsize unit_square = SplineGeometry() From 389280fc0cde72fc331ab79a2d21a815977b2952 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Mon, 19 Oct 2020 16:55:49 +0200 Subject: [PATCH 221/384] debug output --- libsrc/meshing/delaunay2d.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsrc/meshing/delaunay2d.cpp b/libsrc/meshing/delaunay2d.cpp index 66b22708..656dacf6 100644 --- a/libsrc/meshing/delaunay2d.cpp +++ b/libsrc/meshing/delaunay2d.cpp @@ -217,7 +217,7 @@ namespace netgen if(definitive_overlapping_trig==-1) { - cout << "Error in tree - didnt find overlap, check all trigs again" << endl; + PrintMessage (5, "Warning in delaunay tree - didn't find overlapping circle, check all trigs again"); for(auto i_trig : trigs.Range()) { const auto trig = trigs[i_trig]; From 9a39b81615db5611ec336d269a43af2e5c1d849e Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Mon, 19 Oct 2020 17:34:11 +0200 Subject: [PATCH 222/384] fix set csg2d pinfo --- libsrc/geom2d/csg2d.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libsrc/geom2d/csg2d.cpp b/libsrc/geom2d/csg2d.cpp index da236920..f5f85ea7 100644 --- a/libsrc/geom2d/csg2d.cpp +++ b/libsrc/geom2d/csg2d.cpp @@ -1254,6 +1254,7 @@ void CreateResult(Solid2d & sp, Solid2d & sr, bool UNION) if ((status == EXIT) ^ UNION) { vnew.info = V->info; + vnew.pinfo = V->pinfo; if(V->spline) vnew.spline = *V->spline; else @@ -1272,6 +1273,7 @@ void CreateResult(Solid2d & sp, Solid2d & sr, bool UNION) else vnew.spline = nullopt; vnew.info = V->info; + vnew.pinfo = V->pinfo; V->is_intersection = false; // mark visited vertices } if(V == I) @@ -1593,7 +1595,7 @@ Solid2d :: Solid2d(const Array, EdgeInfo, PointInfo>> & po if(auto edge_info = std::get_if(&v)) l.first->prev->info.Assign( *edge_info ); if(auto point_info = std::get_if(&v)) - l.first->pinfo.Assign(*point_info); + l.first->prev->pinfo.Assign(*point_info); } for(auto v : l.Vertices(ALL)) From a2a2da13dc9aef78a2967a91a72c3e42eab0f8e9 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Mon, 19 Oct 2020 19:30:12 +0200 Subject: [PATCH 223/384] debug messages in hp refinement --- libsrc/meshing/hprefinement.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/libsrc/meshing/hprefinement.cpp b/libsrc/meshing/hprefinement.cpp index b7507e33..d27f7a29 100644 --- a/libsrc/meshing/hprefinement.cpp +++ b/libsrc/meshing/hprefinement.cpp @@ -626,7 +626,7 @@ namespace netgen // prepare new points fac1 = max(0.001,min(0.33,fac1)); - cout << " in HP-REFINEMENT with fac1 " << fac1 << endl; + PrintMessage(3, " in HP-REFINEMENT with fac1 ", fac1); *testout << " in HP-REFINEMENT with fac1 " << fac1 << endl; @@ -1283,7 +1283,7 @@ namespace netgen // cout << nwrong << " wrong prisms, " << nright << " right prisms" << endl; } - cout << nwrong << " wrong prisms, " << nright << " right prisms" << endl; + PrintMessage(3, nwrong, " wrong prisms, ", nright, " right prisms"); NgArray hpts(mesh.GetNP()); @@ -1338,7 +1338,7 @@ namespace netgen sing = true; // iterate at least once while(sing) { - cout << " Start new hp-refinement: step " << act_ref << endl; + PrintMessage(3, " Start new hp-refinement: step ", act_ref); DoRefinement (mesh, hpelements, ref, fac1); DoRefineDummies (mesh, hpelements, ref); @@ -1435,16 +1435,16 @@ namespace netgen int(Get_HPRef_Struct (hpel.type) -> geom)); } } - cout << " Start with Update Topology " << endl; + PrintMessage(5, " Start with Update Topology "); mesh.UpdateTopology(); - cout << " Mesh Update Topology done " << endl; + PrintMessage(5, " Mesh Update Topology done "); act_ref++; sing = ClassifyHPElements(mesh,hpelements, act_ref, levels); } - cout << " HP-Refinement done with " << --act_ref << " refinement steps." << endl; + PrintMessage(3, " HP-Refinement done with ", --act_ref, " refinement steps."); if(act_ref>=1) { @@ -1813,7 +1813,7 @@ bool CheckSingularities(Mesh & mesh, INDEX_2_HASHTABLE & edges, INDEX_2_HAS } if (!sing) - cout << "PrepareElements no more to do for actual refinement " << act_ref << endl; + PrintMessage(3, "PrepareElements no more to do for actual refinement ", act_ref); return(sing); } @@ -1960,8 +1960,8 @@ bool CheckSingularities(Mesh & mesh, INDEX_2_HASHTABLE & edges, INDEX_2_HAS } - cout << "undefined elements update classification: " << cnt_undef << endl; - cout << "non-implemented in update classification: " << cnt_nonimplement << endl; + PrintMessage(3, "undefined elements update classification: ", cnt_undef); + PrintMessage(3, "non-implemented in update classification: ", cnt_nonimplement); for (int i = 0; i < misses.Size(); i++) if (misses[i]) From 2d03739f4eeb121c273d6ff7d34c653803e8c73b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20Sch=C3=B6berl?= Date: Tue, 20 Oct 2020 12:35:17 +0200 Subject: [PATCH 224/384] little smooth --- libsrc/csg/specpoin.cpp | 33 ++++++++++++++------------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/libsrc/csg/specpoin.cpp b/libsrc/csg/specpoin.cpp index 33b098f5..e9c4821d 100644 --- a/libsrc/csg/specpoin.cpp +++ b/libsrc/csg/specpoin.cpp @@ -430,27 +430,22 @@ namespace netgen return; } - - auto rev0 = dynamic_cast (geometry->GetSurface(locsurf[0])); - auto rev1 = locsurf.Size() > 1 ? dynamic_cast (geometry->GetSurface(locsurf[1])) : nullptr; - if (numprim == 2 && rev0 && rev1) + + if (numprim == 2) { - NgArray> pts; - bool check = ComputeExtremalPoints (rev0, rev1, pts); - if (check) + auto rev0 = dynamic_cast (geometry->GetSurface(locsurf[0])); + auto rev1 = dynamic_cast (geometry->GetSurface(locsurf[1])); + if (rev0 && rev1) { - // int cnt_inbox = 0; - for (auto p : pts) - if (box.IsIn(p)) - { - AddPoint (p, layer); - // cnt_inbox++; - } - return; - /* - if (cnt_inbox == 0) - return; - */ + NgArray> pts; + bool check = ComputeExtremalPoints (rev0, rev1, pts); + if (check) + { + for (auto p : pts) + if (box.IsIn(p)) + AddPoint (p, layer); + return; + } } } } // end if (numprim <= check_crosspoint) From c2c0bbcbf55053932df3aec2154f10bc44395308 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Tue, 20 Oct 2020 17:17:01 +0200 Subject: [PATCH 225/384] Bugfix on Windows with Python>=3.8 Use os.add_dll_directory() instead of adding netgen bin dir to PATH --- python/__init__.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/python/__init__.py b/python/__init__.py index 17dbdbe1..4d352232 100644 --- a/python/__init__.py +++ b/python/__init__.py @@ -5,7 +5,10 @@ _netgen_bin_dir=os.path.realpath(os.path.join(os.path.dirname(__file__),'..','@N _netgen_lib_dir=os.path.realpath(os.path.join(os.path.dirname(__file__),'..','@NETGEN_PYTHON_RPATH@')) if sys.platform.startswith('win'): - os.environ['PATH'] += ';'+os.path.realpath(os.path.join(os.path.dirname(__file__),'../../../bin')) + if sys.version >= '3.8': + os.add_dll_directory(_netgen_bin_dir) + else: + os.environ['PATH'] += ';'+_netgen_bin_dir del sys del os From 25342f7c3fe22a905b99918658957cb980bbbdcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20Sch=C3=B6berl?= Date: Thu, 22 Oct 2020 12:04:32 +0200 Subject: [PATCH 226/384] speeding up many small domains --- libsrc/geom2d/genmesh2d.cpp | 39 +++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/libsrc/geom2d/genmesh2d.cpp b/libsrc/geom2d/genmesh2d.cpp index 088c4f59..82b9edaa 100644 --- a/libsrc/geom2d/genmesh2d.cpp +++ b/libsrc/geom2d/genmesh2d.cpp @@ -477,6 +477,15 @@ namespace netgen if ( (*mesh)[si].domout > maxdomnr) maxdomnr = (*mesh)[si].domout; } + TableCreator dom2seg_creator(maxdomnr+1); + for ( ; !dom2seg_creator.Done(); dom2seg_creator++) + for (const Segment & seg : mesh->LineSegments()) + { + dom2seg_creator.Add (seg.domin, &seg); + dom2seg_creator.Add (seg.domout, &seg); + } + auto dom2seg = dom2seg_creator.MoveTable(); + mesh->ClearFaceDescriptors(); for (int i = 1; i <= maxdomnr; i++) mesh->AddFaceDescriptor (FaceDescriptor (i, 0, 0, i)); @@ -593,6 +602,7 @@ namespace netgen static Timer t_domain("Mesh domain"); + static Timer t_points("Mesh domain - find points"); for (int domnr = 1; domnr <= maxdomnr; domnr++) { RegionTimer rt(t_domain); @@ -615,6 +625,8 @@ namespace netgen compress = -1; int cnt = 0; + t_points.Start(); + /* for (SegmentIndex si = 0; si < mesh->GetNSeg(); si++) { const auto & s = (*mesh)[si]; @@ -631,9 +643,21 @@ namespace netgen } } } + */ + for (const Segment * seg : dom2seg[domnr]) + if (seg->domin==domnr || seg->domout==domnr ) + for (auto pi : {(*seg)[0], (*seg)[1]}) + if (compress[pi]==-1) + { + meshing.AddPoint((*mesh)[pi], pi); + cnt++; + compress[pi] = cnt; + } + PointGeomInfo gi; gi.trignum = 1; + /* for (SegmentIndex si = 0; si < mesh->GetNSeg(); si++) { if ( (*mesh)[si].domin == domnr) @@ -647,6 +671,21 @@ namespace netgen compress[(*mesh)[si][0]], gi, gi); } } + */ + + for (const Segment * seg : dom2seg[domnr]) + { + if (seg->domin == domnr) + meshing.AddBoundaryElement (compress[(*seg)[0]], + compress[(*seg)[1]], gi, gi); + + if (seg->domout == domnr) + meshing.AddBoundaryElement (compress[(*seg)[1]], + compress[(*seg)[0]], gi, gi); + } + + + t_points.Stop(); if(mp.delaunay2d && cnt>100) meshing.Delaunay(*mesh, domnr, mp); From 832485e41acb20df85c3470db6e467f008e26ae8 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Thu, 22 Oct 2020 12:11:19 +0200 Subject: [PATCH 227/384] pybind11 compatibility --- libsrc/core/python_ngcore.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libsrc/core/python_ngcore.hpp b/libsrc/core/python_ngcore.hpp index 912395b2..634094ad 100644 --- a/libsrc/core/python_ngcore.hpp +++ b/libsrc/core/python_ngcore.hpp @@ -16,8 +16,8 @@ namespace py = pybind11; //////////////////////////////////////////////////////////////////////////////// // automatic conversion of python list to Array<> -PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) -PYBIND11_NAMESPACE_BEGIN(detail) +namespace pybind11 { +namespace detail { template struct ngcore_list_caster { using value_conv = make_caster; @@ -60,8 +60,8 @@ template struct type_caster> : ngcore_list_caster, Type> { }; -PYBIND11_NAMESPACE_END(detail) -PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE) +} // namespace detail +} // namespace pybind11 //////////////////////////////////////////////////////////////////////////////// namespace ngcore From 7f6996aa5d39dfde342520a021618dd503ac7b99 Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Fri, 23 Oct 2020 12:05:30 +0200 Subject: [PATCH 228/384] remove warning output if intersect. triangles in different layers --- libsrc/meshing/meshclass.cpp | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/libsrc/meshing/meshclass.cpp b/libsrc/meshing/meshclass.cpp index 401cd20f..5b7f178c 100644 --- a/libsrc/meshing/meshclass.cpp +++ b/libsrc/meshing/meshclass.cpp @@ -3903,7 +3903,7 @@ namespace netgen (*this)[tri[0]].GetLayer() != (*this)[tri[2]].GetLayer()) { incons_layers = 1; - cout << "inconsistent layers in triangle" << endl; + // cout << "inconsistent layers in triangle" << endl; } const netgen::Point<3> *trip1[3], *trip2[3]; @@ -3917,16 +3917,19 @@ namespace netgen { overlap = 1; lock_guard guard(m); - PrintWarning ("Intersecting elements " - ,int(sei), " and ", int(sej)); + if(!incons_layers) + { + PrintWarning ("Intersecting elements " + ,int(sei), " and ", int(sej)); - (*testout) << "Intersecting: " << endl; - (*testout) << "openelement " << sei << " with open element " << sej << endl; + (*testout) << "Intersecting: " << endl; + (*testout) << "openelement " << sei << " with open element " << sej << endl; - cout << "el1 = " << tri << endl; - cout << "el2 = " << tri2 << endl; - cout << "layer1 = " << (*this)[tri[0]].GetLayer() << endl; - cout << "layer2 = " << (*this)[tri2[0]].GetLayer() << endl; + cout << "el1 = " << tri << endl; + cout << "el2 = " << tri2 << endl; + cout << "layer1 = " << (*this)[tri[0]].GetLayer() << endl; + cout << "layer2 = " << (*this)[tri2[0]].GetLayer() << endl; + } for (int k = 1; k <= 3; k++) (*testout) << tri.PNum(k) << " "; From bfbef5199681c052488ba56bf98158b82abdfbec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20Sch=C3=B6berl?= Date: Fri, 23 Oct 2020 19:40:35 +0200 Subject: [PATCH 229/384] remove bitarray in delaunay2d, just one hashtable position --- libsrc/core/hashtable.hpp | 5 ++++ libsrc/meshing/delaunay2d.cpp | 43 +++++++++++++++++++++++------------ 2 files changed, 33 insertions(+), 15 deletions(-) diff --git a/libsrc/core/hashtable.hpp b/libsrc/core/hashtable.hpp index 72cb73db..00739ffb 100644 --- a/libsrc/core/hashtable.hpp +++ b/libsrc/core/hashtable.hpp @@ -727,6 +727,11 @@ namespace ngcore acont = cont[pos]; } + T GetData (size_t pos) const + { + return cont[pos]; + } + std::pair GetBoth (size_t pos) const { return std::pair (hash[pos], cont[pos]); diff --git a/libsrc/meshing/delaunay2d.cpp b/libsrc/meshing/delaunay2d.cpp index 656dacf6..4f8f5701 100644 --- a/libsrc/meshing/delaunay2d.cpp +++ b/libsrc/meshing/delaunay2d.cpp @@ -66,6 +66,8 @@ namespace netgen Point<2> Center() const { return c; } double Radius2() const { return rad2; } Box<2> BoundingBox() const { return Box<2> (c-Vec<2>(r,r), c+Vec<2>(r,r)); } + + mutable PointIndex visited_pi = -1; }; class DelaunayMesh @@ -132,13 +134,16 @@ namespace netgen Swap(p0,p1); INT<2> hash = {p0,p1}; - auto i2 = edge_to_trig.Get({p0,p1}); - + // auto i2 = edge_to_trig.Get({p0,p1}); + auto pos = edge_to_trig.Position(hash); + auto i2 = edge_to_trig.GetData(pos); + if(i2[0]==eli) i2[0] = i2[1]; i2[1] = -1; - edge_to_trig[hash] = i2; + // edge_to_trig[hash] = i2; + edge_to_trig.SetData (pos, i2); } } @@ -187,6 +192,7 @@ namespace netgen void AddPoint( PointIndex pi_new ) { + static Timer t("AddPoint"); RegionTimer reg(t); Point<2> newp = P2(mesh[pi_new]); intersecting.SetSize(0); edges.SetSize(0); @@ -236,38 +242,45 @@ namespace netgen } } - BitArray trig_visited(trigs.Size()); - trig_visited.Clear(); + // static Timer tvis("trig visited"); + // tvis.Start(); + // BitArray trig_visited(trigs.Size()); + // trig_visited.Clear(); if(definitive_overlapping_trig==-1) throw Exception("point not in any circle "+ ToString(pi_new)); - + // tvis.Stop(); + // static Timer t2("addpoint - rest"); RegionTimer r2(t2); Array trigs_to_visit; trigs_to_visit.Append(definitive_overlapping_trig); intersecting.Append(definitive_overlapping_trig); - trig_visited.SetBit(definitive_overlapping_trig); - + // trig_visited.SetBit(definitive_overlapping_trig); + trigs[definitive_overlapping_trig].visited_pi = pi_new; + while(trigs_to_visit.Size()) { int ti = trigs_to_visit.Last(); trigs_to_visit.DeleteLast(); - trig_visited.SetBit(ti); + // trig_visited.SetBit(ti); auto & trig = trigs[ti]; - + trig.visited_pi = pi_new; + for(auto ei : Range(3)) { auto nb = GetNeighbour(ti, ei); if(nb==-1) continue; - if(trig_visited.Test(nb)) - continue; + // if(trig_visited.Test(nb)) + // continue; const auto & trig_nb = trigs[nb]; + if (trig_nb.visited_pi == pi_new) + continue; - - trig_visited.SetBit(nb); - + // trig_visited.SetBit(nb); + trig_nb.visited_pi = pi_new; + bool is_intersecting = Dist2(newp, trig_nb.Center()) < trig_nb.Radius2()*(1+1e-12); if(!is_intersecting) From 11557838a4023d837b9d8a3fddb4f357c300b349 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20Sch=C3=B6berl?= Date: Sun, 25 Oct 2020 09:51:57 +0100 Subject: [PATCH 230/384] tuning of Delaunay2d: FindInnerPoints, use of edgeHT --- libsrc/meshing/adfront2.cpp | 2 +- libsrc/meshing/adfront2.hpp | 2 +- libsrc/meshing/delaunay2d.cpp | 48 ++++++++++++-- libsrc/meshing/localh.cpp | 115 +++++++++++++++++++--------------- libsrc/meshing/localh.hpp | 10 ++- 5 files changed, 115 insertions(+), 62 deletions(-) diff --git a/libsrc/meshing/adfront2.cpp b/libsrc/meshing/adfront2.cpp index fc858ca4..29643699 100644 --- a/libsrc/meshing/adfront2.cpp +++ b/libsrc/meshing/adfront2.cpp @@ -503,7 +503,7 @@ namespace netgen } bool AdFront2 :: SameSide (const Point<2> & lp1, const Point<2> & lp2, - const NgArray * testfaces) const + const FlatArray * testfaces) const { int cnt = 0; diff --git a/libsrc/meshing/adfront2.hpp b/libsrc/meshing/adfront2.hpp index 5758c184..dfed1b21 100644 --- a/libsrc/meshing/adfront2.hpp +++ b/libsrc/meshing/adfront2.hpp @@ -262,7 +262,7 @@ public: bool Inside (const Point<2> & p) const; bool SameSide (const Point<2> & lp1, const Point<2> & lp2, - const NgArray * /* testfaces */ = NULL) const; + const FlatArray * /* testfaces */ = NULL) const; /* { return Inside (lp1) == Inside (lp2); diff --git a/libsrc/meshing/delaunay2d.cpp b/libsrc/meshing/delaunay2d.cpp index 4f8f5701..14a7d68f 100644 --- a/libsrc/meshing/delaunay2d.cpp +++ b/libsrc/meshing/delaunay2d.cpp @@ -89,12 +89,18 @@ namespace netgen Swap(p0,p1); INT<2> hash = {p0,p1}; + /* if(!edge_to_trig.Used(hash)) return -1; auto i2 = edge_to_trig.Get({p0,p1}); return i2[0] == eli ? i2[1] : i2[0]; + */ + auto pos = edge_to_trig.Position(hash); + if (pos == -1) return -1; + auto i2 = edge_to_trig.GetData(pos); + return i2[0] == eli ? i2[1] : i2[0]; } void SetNeighbour( int eli, int edge ) @@ -105,6 +111,22 @@ namespace netgen Swap(p0,p1); INT<2> hash = {p0,p1}; + auto pos = edge_to_trig.Position(hash); + if (pos == -1) + edge_to_trig[hash] = {eli, -1}; + else + { + auto i2 = edge_to_trig.GetData(pos); + if(i2[0]==-1) + i2[0] = eli; + else + { + if(i2[1]==-1) + i2[1] = eli; + } + edge_to_trig.SetData (pos, i2); + } + /* if(!edge_to_trig.Used(hash)) edge_to_trig[hash] = {eli, -1}; else @@ -122,6 +144,7 @@ namespace netgen edge_to_trig[hash] = i2; } + */ } void UnsetNeighbours( int eli ) @@ -477,18 +500,31 @@ namespace netgen *testout << "npoints = " << endl << npoints << endl; } - for (int i = 1; i <= npoints.Size(); i++) + + int prims[] = { 211, 223, 227, 229, 233, 239, 241, 251, 257, 263 }; + int prim; + + { + int i = 0; + while (npoints.Size() % prims[i] == 0) i++; + prim = prims[i]; + } + + + for (int i = 0; i < npoints.Size(); i++) { - if (meshbox.IsIn (npoints.Get(i))) + size_t hi = (size_t(prim) * size_t(i)) % npoints.Size(); + + if (meshbox.IsIn (npoints[hi])) { - PointIndex gpnum = mesh.AddPoint (npoints.Get(i)); - adfront.AddPoint (npoints.Get(i), gpnum); + PointIndex gpnum = mesh.AddPoint (npoints[hi]); + adfront.AddPoint (npoints[hi], gpnum); if (debugparam.slowchecks) { - (*testout) << npoints.Get(i) << endl; + (*testout) << npoints[hi] << endl; - Point<2> p2d (npoints.Get(i)(0), npoints.Get(i)(1)); + Point<2> p2d (npoints[hi](0), npoints[hi](1)); if (!adfront.Inside(p2d)) { cout << "add outside point" << endl; diff --git a/libsrc/meshing/localh.cpp b/libsrc/meshing/localh.cpp index d8445b11..06ff3334 100644 --- a/libsrc/meshing/localh.cpp +++ b/libsrc/meshing/localh.cpp @@ -569,84 +569,72 @@ namespace netgen int nf = adfront->GetNFL(); - NgArray faceinds(nf); - NgArray > faceboxes(nf); + Array faceinds(nf); + Array> faceboxes(nf); for (int i = 0; i < nf; i++) { faceinds[i] = i; - // adfront->GetFaceBoundingBox(i, faceboxes.Elem(i)); - const FrontLine & line = adfront->GetLine(i); - faceboxes[i].Set (adfront->GetPoint (line.L().I1())); - faceboxes[i].Add (adfront->GetPoint (line.L().I2())); + Point<3> p1 = adfront->GetPoint (line.L().I1()); + Point<3> p2 = adfront->GetPoint (line.L().I2()); + + faceboxes[i].Set (Point<2> (p1(0), p1(1))); + faceboxes[i].Add (Point<2> (p2(0), p2(1))); } for (int i = 0; i < 8; i++) - FindInnerBoxesRec2 (root->childs[i], adfront, faceboxes, faceinds, nf); + FindInnerBoxesRec2 (root->childs[i], adfront, faceboxes, faceinds); // , nf); } void LocalH :: FindInnerBoxesRec2 (GradingBox * box, class AdFront2 * adfront, - NgArray > & faceboxes, - NgArray & faceinds, int nfinbox) + FlatArray> faceboxes, + FlatArray faceinds) // , int nfinbox) { if (!box) return; + + GradingBox * father = box -> father; - GradingBox * father = box -> father; - - Point3d c(box->xmid[0], box->xmid[1], 0); // box->xmid[2]); - Vec3d v(box->h2, box->h2, box->h2); - Box3d boxc(c-v, c+v); - - Point3d fc(father->xmid[0], father->xmid[1], 0); // father->xmid[2]); - Vec3d fv(father->h2, father->h2, father->h2); - Box3d fboxc(fc-fv, fc+fv); - Box3d boxcfc(c,fc); - - NgArrayMem faceused; - NgArrayMem faceused2; - NgArrayMem facenotused; - - for (int j = 0; j < nfinbox; j++) - { - // adfront->GetFaceBoundingBox (faceinds.Get(j), facebox); - const Box3d & facebox = faceboxes[faceinds[j]]; - - if (boxc.Intersect (facebox)) - faceused.Append(faceinds[j]); - else - facenotused.Append(faceinds[j]); - - if (boxcfc.Intersect (facebox)) - faceused2.Append (faceinds[j]); - } - - for (int j = 0; j < faceused.Size(); j++) - faceinds[j] = faceused[j]; - for (int j = 0; j < facenotused.Size(); j++) - faceinds[j+faceused.Size()] = facenotused[j]; - if (!father->flags.cutboundary) { box->flags.isinner = father->flags.isinner; box->flags.pinner = father->flags.pinner; } else - { - Point3d cf(father->xmid[0], father->xmid[1], father->xmid[2]); - + { if (father->flags.isinner) { box->flags.pinner = 1; } else { - Point<2> c2d (c.X(), c.Y()); - Point<2> cf2d (cf.X(), cf.Y()); - bool sameside = adfront->SameSide (c2d, cf2d, &faceused2); + Point<2> c(box->xmid[0], box->xmid[1]); + Point<2> fc(father->xmid[0], father->xmid[1]); + Box<2> boxcfc(c,fc); + + // reorder: put faces cutting boxcfc first: + int iused = 0; + int inotused = faceinds.Size()-1; + while (iused <= inotused) + { + while ( (iused <= inotused) && boxcfc.Intersect (faceboxes[faceinds[iused]])) + iused++; + while ( (iused <= inotused) && !boxcfc.Intersect (faceboxes[faceinds[inotused]])) + inotused--; + if (iused < inotused) + { + Swap (faceinds[iused], faceinds[inotused]); + iused++; + inotused--; + } + } + + // bool sameside = adfront->SameSide (c2d, cf2d, &faceused2); + auto sub = faceinds.Range(0, iused); + bool sameside = adfront->SameSide (c, fc, &sub); if (sameside) box->flags.pinner = father->flags.pinner; else @@ -659,11 +647,34 @@ namespace netgen box->flags.isinner = box->flags.pinner; } - // cout << "faceused: " << faceused.Size() << ", " << faceused2.Size() << ", " << facenotused.Size() << endl; - int nf = faceused.Size(); + + int iused = 0; + if (faceinds.Size()) + { + Point<2> c(box->xmid[0], box->xmid[1]); // box->xmid[2]); + Vec<2> v(box->h2, box->h2); + Box<2> boxc(c-v, c+v); + + // reorder again: put faces cutting boxc first: + int inotused = faceinds.Size()-1; + while (iused <= inotused) + { + while ( (iused <= inotused) && boxc.Intersect (faceboxes[faceinds[iused]])) + iused++; + while ( (iused <= inotused) && !boxc.Intersect (faceboxes[faceinds[inotused]])) + inotused--; + if (iused < inotused) + { + Swap (faceinds[iused], faceinds[inotused]); + iused++; + inotused--; + } + } + } + for (int i = 0; i < 8; i++) - FindInnerBoxesRec2 (box->childs[i], adfront, faceboxes, faceinds, nf); + FindInnerBoxesRec2 (box->childs[i], adfront, faceboxes, faceinds.Range(0,iused)); } diff --git a/libsrc/meshing/localh.hpp b/libsrc/meshing/localh.hpp index d15b11cd..0a811795 100644 --- a/libsrc/meshing/localh.hpp +++ b/libsrc/meshing/localh.hpp @@ -30,10 +30,16 @@ namespace netgen struct { + /* unsigned int cutboundary:1; unsigned int isinner:1; unsigned int oldcell:1; unsigned int pinner:1; + */ + bool cutboundary; + bool isinner; + bool oldcell; + bool pinner; } flags; /// @@ -158,8 +164,8 @@ namespace netgen /// void FindInnerBoxesRec2 (GradingBox * box, class AdFront2 * adfront, - NgArray > & faceboxes, - NgArray & finds, int nfinbox); + FlatArray> faceboxes, + FlatArray finds); // , int nfinbox); From de83f0ca14c3cd7cf42b3fdafa8f118b1520ce67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20Sch=C3=B6berl?= Date: Sun, 25 Oct 2020 16:31:47 +0100 Subject: [PATCH 231/384] Delaunay2d also for small sub-domains --- libsrc/geom2d/genmesh2d.cpp | 4 +- libsrc/meshing/adfront2.hpp | 2 +- libsrc/meshing/delaunay2d.cpp | 79 +++++++++++++++++++++++++++++++---- libsrc/meshing/localh.cpp | 56 +++++++++++++++++++++---- libsrc/meshing/localh.hpp | 5 ++- 5 files changed, 125 insertions(+), 21 deletions(-) diff --git a/libsrc/geom2d/genmesh2d.cpp b/libsrc/geom2d/genmesh2d.cpp index 82b9edaa..4ddd0370 100644 --- a/libsrc/geom2d/genmesh2d.cpp +++ b/libsrc/geom2d/genmesh2d.cpp @@ -687,7 +687,7 @@ namespace netgen t_points.Stop(); - if(mp.delaunay2d && cnt>100) + if(mp.delaunay2d && cnt>1) meshing.Delaunay(*mesh, domnr, mp); else { @@ -707,6 +707,8 @@ namespace netgen mesh->SetMaterial (domnr, material); } + mesh->Compress(); + mp.quad = hquad; diff --git a/libsrc/meshing/adfront2.hpp b/libsrc/meshing/adfront2.hpp index dfed1b21..95914535 100644 --- a/libsrc/meshing/adfront2.hpp +++ b/libsrc/meshing/adfront2.hpp @@ -206,7 +206,7 @@ public: const FrontLine & GetLine (int nr) { return lines[nr]; } const FrontPoint2 & GetPoint (int nr) { return points[nr]; } - + const auto & GetLines () const { return lines; } /// int SelectBaseLine (Point<3> & p1, Point<3> & p2, diff --git a/libsrc/meshing/delaunay2d.cpp b/libsrc/meshing/delaunay2d.cpp index 14a7d68f..75925e1c 100644 --- a/libsrc/meshing/delaunay2d.cpp +++ b/libsrc/meshing/delaunay2d.cpp @@ -454,8 +454,14 @@ namespace netgen bool changed; do { - mesh.LocalHFunction().ClearFlags(); - + static Timer tcf("clear flags"); + tcf.Start(); + // mesh.LocalHFunction().ClearFlags(); + mesh.LocalHFunction().ClearRootFlags(); + tcf.Stop(); + + static Timer tcut("tcut"); + tcut.Start(); for (int i = 0; i < adfront.GetNFL(); i++) { const FrontLine & line = adfront.GetLine(i); @@ -469,7 +475,7 @@ namespace netgen mesh.LocalHFunction().CutBoundary (bbox); } - + tcut.Stop(); mesh.LocalHFunction().FindInnerBoxes (&adfront, NULL); @@ -506,11 +512,11 @@ namespace netgen { int i = 0; - while (npoints.Size() % prims[i] == 0) i++; + if (npoints.Size()) + while (npoints.Size() % prims[i] == 0) i++; prim = prims[i]; } - for (int i = 0; i < npoints.Size(); i++) { size_t hi = (size_t(prim) * size_t(i)) % npoints.Size(); @@ -570,7 +576,8 @@ namespace netgen // outer points : smooth mesh-grading npoints.SetSize(0); loch2.GetOuterPoints (npoints); - + + /* for (int i = 1; i <= npoints.Size(); i++) { if (meshbox.IsIn (npoints.Get(i))) @@ -579,7 +586,14 @@ namespace netgen adfront.AddPoint (npoints.Get(i), gpnum); } } + */ + for (const Point<3> p : npoints) + if (meshbox.IsIn(p)) + { + PointIndex gpnum = mesh.AddPoint (p); + adfront.AddPoint (p, gpnum); + } timer4.Stop(); } @@ -589,6 +603,9 @@ namespace netgen void Meshing2 :: Delaunay (Mesh & mesh, int domainnr, const MeshingParameters & mp) { static Timer timer("Meshing2::Delaunay"); + static Timer t1("Meshing2::Delaunay1"); + static Timer t2("Meshing2::Delaunay2"); + static Timer t3("Meshing2::Delaunay3"); static Timer timer_addpoints("add points"); RegionTimer reg (timer); @@ -600,6 +617,7 @@ namespace netgen auto last_point_blockfill = mesh.Points().Range().Next(); + t1.Start(); // Bounding box for starting trig in delaunay Box<2> bbox (Box<2>::EMPTY_BOX); @@ -615,10 +633,14 @@ namespace netgen for (int i = 0; i < mesh.LockedPoints().Size(); i++) bbox.Add (P2(mesh.Point (mesh.LockedPoints()[i]))); + t1.Stop(); + t2.Start(); Array old_points; BitArray add_point(mesh.Points().Size()+1); + Array addpoints; add_point.Clear(); + /* for (SegmentIndex si = 0; si < mesh.GetNSeg(); si++) { const auto & s = mesh[si]; @@ -628,7 +650,28 @@ namespace netgen add_point.SetBit(s[1]); } } + */ + /* + for (int i = 0; i < adfront.GetNFL(); i++) + { + const FrontLine & line = adfront.GetLine(i); + for (int j = 0; j < 2; j++) + add_point.SetBit (adfront.GetGlobalIndex (line.L()[j]))adfront.GetGlobalIndex (line.L()[j])); + } + */ + for (const auto & line : adfront.GetLines()) + for (int j = 0; j < 2; j++) + { + PointIndex pnum = adfront.GetGlobalIndex (line.L()[j]); + if (!add_point.Test(pnum)) + addpoints.Append(pnum); + add_point.SetBit (pnum); + } + + + t2.Stop(); + t3.Start(); Mesh tempmesh; tempmesh.AddFaceDescriptor (FaceDescriptor (1, 1, 0, 0)); tempmesh.AddFaceDescriptor (FaceDescriptor (2, 1, 0, 0)); @@ -637,8 +680,11 @@ namespace netgen Array compress; Array icompress(mesh.Points().Size()); + /* for(auto pi : mesh.Points().Range()) if(add_point.Test(pi)) + */ + for (PointIndex pi : addpoints) { icompress[pi] = tempmesh.AddPoint(mesh[pi]); compress.Append(pi); @@ -649,7 +695,7 @@ namespace netgen icompress[pi] = tempmesh.AddPoint(mesh[pi]); compress.Append(pi); } - + t3.Stop(); // DelaunayMesh adds surrounding trig (don't add the last 3 points to delaunay AGAIN! auto tempmesh_points = tempmesh.Points().Range(); @@ -676,7 +722,10 @@ namespace netgen timer_addpoints.Stop(); + static Timer taddseg("addseg"); + taddseg.Start(); + /* for (auto seg : mesh.LineSegments()) { if ( seg.domin == domainnr || seg.domout == domainnr ) @@ -690,7 +739,19 @@ namespace netgen tempmesh.AddSegment(seg); } } - + */ + for (const auto & line : adfront.GetLines()) + { + Segment seg; + for (int j = 0; j < 2; j++) + seg[j] = icompress [adfront.GetGlobalIndex (line.L()[j])]; + seg.domin = domainnr; + seg.domout = 0; + tempmesh.AddSegment(seg); + } + + taddseg.Stop(); + for (auto & trig : dmesh.GetElements()) { if (trig[0] < 0) continue; @@ -883,7 +944,7 @@ namespace netgen } } - mesh.Compress(); + // mesh.Compress(); // don't compress whole mesh after every sub-domain } } diff --git a/libsrc/meshing/localh.cpp b/libsrc/meshing/localh.cpp index 06ff3334..32298191 100644 --- a/libsrc/meshing/localh.cpp +++ b/libsrc/meshing/localh.cpp @@ -381,7 +381,12 @@ namespace netgen return; } - box->flags.cutboundary = 1; + if (!box->flags.cutboundary) + for (int i = 0; i < 8; i++) + if (box->childs[i]) + box->childs[i]->flags.cutboundary = false; + + box->flags.cutboundary = true; for (int i = 0; i < 8; i++) if (box->childs[i]) CutBoundaryRec (pmin, pmax, box->childs[i]); @@ -547,13 +552,19 @@ namespace netgen void LocalH :: FindInnerBoxes (AdFront2 * adfront, int (*testinner)(const Point<2> & p1)) { - static int timer = NgProfiler::CreateTimer ("LocalH::FindInnerBoxes 2d"); - NgProfiler::RegionTimer reg (timer); + static Timer t("LocalH::FindInnerBoxes 2d"); RegionTimer reg (t); + static Timer trec("LocalH::FindInnerBoxes 2d - rec"); + static Timer tinit("LocalH::FindInnerBoxes 2d - init"); + /* + tinit.Start(); for (int i = 0; i < boxes.Size(); i++) boxes[i] -> flags.isinner = 0; - + tinit.Stop(); + */ + root->flags.isinner = 0; + root->flags.cutboundary = true; Point<2> rpmid(root->xmid[0], root->xmid[1]); // , root->xmid[2]); Vec<2> rv(root->h2, root->h2); @@ -582,7 +593,8 @@ namespace netgen faceboxes[i].Set (Point<2> (p1(0), p1(1))); faceboxes[i].Add (Point<2> (p2(0), p2(1))); } - + + RegionTimer regrc(trec); for (int i = 0; i < 8; i++) FindInnerBoxesRec2 (root->childs[i], adfront, faceboxes, faceinds); // , nf); } @@ -602,11 +614,13 @@ namespace netgen { box->flags.isinner = father->flags.isinner; box->flags.pinner = father->flags.pinner; + box->flags.cutboundary = false; } else { if (father->flags.isinner) { + cout << "how is this possible ???" << endl; box->flags.pinner = 1; } else @@ -672,9 +686,11 @@ namespace netgen } } } - - for (int i = 0; i < 8; i++) - FindInnerBoxesRec2 (box->childs[i], adfront, faceboxes, faceinds.Range(0,iused)); + + + if (box->flags.isinner || box->flags.cutboundary) + for (int i = 0; i < 8; i++) + FindInnerBoxesRec2 (box->childs[i], adfront, faceboxes, faceinds.Range(0,iused)); } @@ -720,6 +736,13 @@ namespace netgen ClearFlagsRec (box->childs[i]); } + void LocalH :: ClearRootFlags () + { + root->flags.cutboundary = false; + root->flags.isinner = false; + } + + void LocalH :: ClearFlagsRec (GradingBox * box) { box->flags.cutboundary = 0; @@ -746,13 +769,17 @@ namespace netgen } } - void LocalH :: GetInnerPoints (NgArray > & points) + void LocalH :: GetInnerPoints (NgArray > & points) const { + static Timer t("GetInnerPoints"); RegionTimer reg(t); if (dimension == 2) { + GetInnerPointsRec (root, points); + /* for (int i = 0; i < boxes.Size(); i++) if (boxes[i] -> flags.isinner && boxes[i] -> HasChilds()) points.Append ( boxes[i] -> PMid() ); + */ } else { @@ -763,7 +790,18 @@ namespace netgen } + void LocalH :: GetInnerPointsRec (const GradingBox * box, NgArray > & points) const + { + if (box -> flags.isinner && box -> HasChilds()) + points.Append ( box -> PMid() ); + if (box->flags.isinner || box->flags.cutboundary) + for (int i = 0; i < 8; i++) + if (box->childs[i]) + GetInnerPointsRec (box->childs[i], points); + } + + void LocalH :: GetOuterPoints (NgArray > & points) { for (int i = 0; i < boxes.Size(); i++) diff --git a/libsrc/meshing/localh.hpp b/libsrc/meshing/localh.hpp index 0a811795..4f6881a0 100644 --- a/libsrc/meshing/localh.hpp +++ b/libsrc/meshing/localh.hpp @@ -121,11 +121,14 @@ namespace netgen void ClearFlags () { ClearFlagsRec(root); } + void ClearRootFlags (); + /// widen refinement zone void WidenRefinement (); /// get points in inner elements - void GetInnerPoints (NgArray > & points); + void GetInnerPoints (NgArray > & points) const; + void GetInnerPointsRec (const GradingBox * box, NgArray > & points) const; /// get points in outer closure void GetOuterPoints (NgArray > & points); From cddfb4a0b50620acbdee6891870696356170aa30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20Sch=C3=B6berl?= Date: Mon, 26 Oct 2020 11:20:12 +0100 Subject: [PATCH 232/384] fixing delaunay2d point search, non-parallel for small meshes --- libsrc/core/table.cpp | 13 +++++++++++++ libsrc/core/taskmanager.cpp | 19 +++++++++++++++++++ libsrc/meshing/delaunay2d.cpp | 23 +++++++++++++++++++++-- libsrc/meshing/meshclass.cpp | 7 +++++-- 4 files changed, 58 insertions(+), 4 deletions(-) diff --git a/libsrc/core/table.cpp b/libsrc/core/table.cpp index ad69694b..1fbcda75 100644 --- a/libsrc/core/table.cpp +++ b/libsrc/core/table.cpp @@ -18,6 +18,19 @@ namespace ngcore size_t size = entrysize.Size(); size_t * index = new size_t[size+1]; + if (entrysize.Size() < 100) + { + size_t mysum = 0; + for (size_t i = 0; i < entrysize.Size(); i++) + { + index[i] = mysum; + mysum += entrysize[i]; + } + index[entrysize.Size()] = mysum; + return index; + } + + Array partial_sums(TaskManager::GetNumThreads()+1); partial_sums[0] = 0; ParallelJob diff --git a/libsrc/core/taskmanager.cpp b/libsrc/core/taskmanager.cpp index 4a49adff..be345321 100644 --- a/libsrc/core/taskmanager.cpp +++ b/libsrc/core/taskmanager.cpp @@ -337,6 +337,25 @@ namespace ngcore return; } + if (antasks == 1) + { + if (trace) + trace->StartJob(jobnr, afunc.target_type()); + jobnr++; + if (startup_function) (*startup_function)(); + TaskInfo ti; + ti.task_nr = 0; + ti.ntasks = 1; + ti.thread_nr = 0; ti.nthreads = 1; + { + RegionTracer t(ti.thread_nr, jobnr, RegionTracer::ID_JOB, ti.task_nr); + afunc(ti); + } + if (cleanup_function) (*cleanup_function)(); + if (trace) + trace->StopJob(); + return; + } if (trace) trace->StartJob(jobnr, afunc.target_type()); diff --git a/libsrc/meshing/delaunay2d.cpp b/libsrc/meshing/delaunay2d.cpp index 75925e1c..55538ad6 100644 --- a/libsrc/meshing/delaunay2d.cpp +++ b/libsrc/meshing/delaunay2d.cpp @@ -45,8 +45,10 @@ namespace netgen Point<2> p1 = P2(mesh[pnums[0]]); Point<2> p2 = P2(mesh[pnums[1]]); Point<2> p3 = P2(mesh[pnums[2]]); + Vec<2> v1 = p2-p1; Vec<2> v2 = p3-p1; + /* Mat<2,2> mat, inv; mat(0,0) = v1*v1; mat(0,1) = v1*v2; @@ -60,7 +62,22 @@ namespace netgen c = p1 + sol(0) * v1 + sol(1) * v2; rad2 = Dist2(c, p1); - r = sqrt(rad2); + r = sqrt(rad2); + */ + + // without normal equation ... + Mat<2,2> mat, inv; + mat(0,0) = v1(0); mat(0,1) = v1(1); + mat(1,0) = v2(0); mat(1,1) = v2(1); + CalcInverse (mat, inv); + Vec<2> rhs, sol; + rhs(0) = 0.5 * v1*v1; + rhs(1) = 0.5 * v2*v2; + sol = inv * rhs; + c = p1 + sol; + + rad2 = Dist2(c, p1); + r = sqrt(rad2); } Point<2> Center() const { return c; } @@ -246,6 +263,7 @@ namespace netgen if(definitive_overlapping_trig==-1) { + static Timer t("slow check"); RegionTimer reg(t); PrintMessage (5, "Warning in delaunay tree - didn't find overlapping circle, check all trigs again"); for(auto i_trig : trigs.Range()) { @@ -257,7 +275,8 @@ namespace netgen double rad2 = trig.Radius2(); double d2 = Dist2 (trig.Center(), newp); - if (d2 < 0.999 * rad2) + // if (d2 < 0.999 * rad2) + if (d2 < (1-1e-10)*rad2) { definitive_overlapping_trig = i_trig; break; diff --git a/libsrc/meshing/meshclass.cpp b/libsrc/meshing/meshclass.cpp index 5b7f178c..d9d7e415 100644 --- a/libsrc/meshing/meshclass.cpp +++ b/libsrc/meshing/meshclass.cpp @@ -6410,7 +6410,9 @@ namespace netgen for (SurfaceElementIndex ei : myrange) for (PointIndex pi : (*this)[ei].PNums()) creator.Add (pi, ei); - }, ngcore::TasksPerThread(4)); + }, + // ngcore::TasksPerThread(4)); + (surfelements.Size()>100) ? ngcore::TasksPerThread(4) : 1); } else { @@ -6432,7 +6434,8 @@ namespace netgen { for (PointIndex pi : myrange) QuickSort(elementsonnode[pi]); - }); + }, + (surfelements.Size()>100) ? ngcore::TasksPerThread(1) : 1); return move(elementsonnode); } From a3391519f0a4220cde5373e9a5151780d1f523d9 Mon Sep 17 00:00:00 2001 From: Michael Date: Tue, 27 Oct 2020 07:54:26 +0100 Subject: [PATCH 233/384] add GeomInfo for bisecting quads --- libsrc/meshing/bisect.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/libsrc/meshing/bisect.cpp b/libsrc/meshing/bisect.cpp index 1f9bbba8..5127c439 100644 --- a/libsrc/meshing/bisect.cpp +++ b/libsrc/meshing/bisect.cpp @@ -1082,8 +1082,12 @@ namespace netgen MarkedQuad & mq) { for (int i = 0; i < 4; i++) - mq.pnums[i] = el[i]; - Swap (mq.pnums[2], mq.pnums[3]); + { + mq.pnums[i] = el[i]; + mq.pgeominfo[i] = el.GeomInfoPi (i+1); + } + Swap (mq.pnums[2], mq.pnums[3]); + Swap (mq.pgeominfo[2], mq.pgeominfo[3]); mq.marked = 0; mq.markededge = 0; From 4a1d3cdcb2002b93de58a1c0689aa9cd488ba754 Mon Sep 17 00:00:00 2001 From: Michael Date: Tue, 27 Oct 2020 07:57:17 +0100 Subject: [PATCH 234/384] save/load mesh bbbnd --- libsrc/meshing/meshclass.cpp | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/libsrc/meshing/meshclass.cpp b/libsrc/meshing/meshclass.cpp index 401cd20f..572547b9 100644 --- a/libsrc/meshing/meshclass.cpp +++ b/libsrc/meshing/meshclass.cpp @@ -677,6 +677,18 @@ namespace netgen outfile << endl << endl; } + int cntcd3names = 0; + for (int ii = 0; ii> n; + NgArray cd3nrs(n); + SetNCD3Names(n); + for( i=1; i<=n; i++) + { + string nextcd3name; + infile >> cd3nrs[i-1] >> nextcd3name; + cd3names[cd3nrs[i-1]-1] = new string(nextcd3name); + } + if (GetDimension() < 3) + { + throw NgException("co dim 3 elements not implemented for dimension < 3"); + } + } + if (strcmp (str, "singular_points") == 0) { infile >> n; From 47632a06aab3e04536482300cfffd57660771601 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Tue, 27 Oct 2020 14:54:25 +0100 Subject: [PATCH 235/384] fix index error in cgns import --- libsrc/interface/rw_cgns.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsrc/interface/rw_cgns.cpp b/libsrc/interface/rw_cgns.cpp index a21fdca9..13010fae 100644 --- a/libsrc/interface/rw_cgns.cpp +++ b/libsrc/interface/rw_cgns.cpp @@ -677,7 +677,7 @@ namespace netgen for (auto sei : Range(mesh.SurfaceElements())) { int ei0, ei1; - topo.GetSurface2VolumeElement (sei, ei0, ei1); + topo.GetSurface2VolumeElement (sei+1, ei0, ei1); auto si = mesh.SurfaceElement(sei).GetIndex(); auto & fd = mesh.GetFaceDescriptor(si); From d40c05b1b170c14db8c94e94d013e46a8c608a04 Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Tue, 27 Oct 2020 16:53:07 +0100 Subject: [PATCH 236/384] fix not working boundarylayer test --- tests/pytest/test_boundarylayer.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/tests/pytest/test_boundarylayer.py b/tests/pytest/test_boundarylayer.py index f9e86caa..733aa0dc 100644 --- a/tests/pytest/test_boundarylayer.py +++ b/tests/pytest/test_boundarylayer.py @@ -2,11 +2,15 @@ import pytest from netgen.csg import * -def GetNSurfaceElements(mesh, boundaries): +def GetNSurfaceElements(mesh, boundaries, adjacent_domain=None): nse_in_layer = 0 for el in mesh.Elements2D(): if mesh.GetBCName(el.index-1) in boundaries: - nse_in_layer += 1 + if adjacent_domain is None: + nse_in_layer += 1 + else: + if (mesh.FaceDescriptor(el.index).domin > 0 and mesh.GetMaterial(mesh.FaceDescriptor(el.index).domin) == adjacent_domain) or (mesh.FaceDescriptor(el.index).domout > 0 and mesh.GetMaterial(mesh.FaceDescriptor(el.index).domout) == adjacent_domain): + nse_in_layer += 1 return nse_in_layer @pytest.mark.parametrize("outside", [True, False]) @@ -29,7 +33,7 @@ def test_boundarylayer(outside, capfd): assert not "elements are not matching" in capture.out @pytest.mark.parametrize("outside", [True, False]) -@pytest.mark.parametrize("version", [1]) # version 2 not working yet +@pytest.mark.parametrize("version", [1, 2]) # version 2 not working yet def test_boundarylayer2(outside, version, capfd): geo = CSGeometry() top = Plane(Pnt(0,0,0.5), Vec(0,0,1)) @@ -48,7 +52,7 @@ def test_boundarylayer2(outside, version, capfd): geo.CloseSurfaces(top, bot, []) mesh = geo.GenerateMesh() - should_ne = mesh.ne + 2 * GetNSurfaceElements(mesh, ["default"]) + should_ne = mesh.ne + 2 * GetNSurfaceElements(mesh, ["default"], "part") layersize = 0.05 mesh.BoundaryLayer("default", [0.5 * layersize, layersize], "layer", domains="part", outside=outside, grow_edges=True) assert mesh.ne == should_ne From 31c72299c429ccdfbcd03c8a24a9b3b80d5f7022 Mon Sep 17 00:00:00 2001 From: Michael Date: Fri, 30 Oct 2020 14:10:52 +0100 Subject: [PATCH 237/384] add hp refinement possibility for surface geometry --- libsrc/meshing/python_mesh.cpp | 24 ++++++- libsrc/meshing/surfacegeom.cpp | 127 +++++++++++++++++++++++++-------- libsrc/meshing/surfacegeom.hpp | 5 +- 3 files changed, 124 insertions(+), 32 deletions(-) diff --git a/libsrc/meshing/python_mesh.cpp b/libsrc/meshing/python_mesh.cpp index c1cbb0c5..9f7be124 100644 --- a/libsrc/meshing/python_mesh.cpp +++ b/libsrc/meshing/python_mesh.cpp @@ -1246,27 +1246,45 @@ grow_edges : bool = False }), py::arg("mapping")) .def(NGSPickle()) .def("GenerateMesh", [](shared_ptr geo, - bool quads, int nx, int ny, bool flip_triangles, py::list py_bbbpts, py::list py_bbbnames) + bool quads, int nx, int ny, bool flip_triangles, py::list py_bbbpts, py::list py_bbbnames, py::list py_hppts, py::list py_hpbnd) { if (py::len(py_bbbpts) != py::len(py_bbbnames)) throw Exception("In SurfaceGeometry::GenerateMesh bbbpts and bbbnames do not have same lengths."); Array> bbbpts(py::len(py_bbbpts)); Array bbbname(py::len(py_bbbpts)); + Array> hppts(py::len(py_hppts)); + Array hpptsfac(py::len(py_hppts)); + Array hpbnd(py::len(py_hpbnd)); + Array hpbndfac(py::len(py_hpbnd)); for(int i = 0; i(py_bbbpts[i])(); bbbpts[i] = Point<3>(py::extract(pnt[0])(),py::extract(pnt[1])(),py::extract(pnt[2])()); bbbname[i] = py::extract(py_bbbnames[i])(); } + for(int i = 0; i(py_hppts[i])(); + hppts[i] = Point<3>(py::extract(pnt[0])(),py::extract(pnt[1])(),py::extract(pnt[2])()); + //hpptsfac[i] = py::len(pnt) > 3 ? py::extract(pnt[3])() : 0.0; + hpptsfac[i] = py::extract(pnt[3])(); + } + + for(int i = 0; i(py_hpbnd[i])(); + hpbnd[i] = py::extract(bnd[0])(); + hpbndfac[i] = py::extract(bnd[1])(); + } auto mesh = make_shared(); SetGlobalMesh (mesh); mesh->SetGeometry(geo); ng_geometry = geo; - auto result = geo->GenerateMesh (mesh, quads, nx, ny, flip_triangles, bbbpts, bbbname); + auto result = geo->GenerateMesh (mesh, quads, nx, ny, flip_triangles, bbbpts, bbbname, hppts, hpptsfac, hpbnd, hpbndfac); if(result != 0) throw Exception("SurfaceGeometry: Meshing failed!"); return mesh; - }, py::arg("quads")=true, py::arg("nx")=10, py::arg("ny")=10, py::arg("flip_triangles")=false, py::arg("bbbpts")=py::list(), py::arg("bbbnames")=py::list()) + }, py::arg("quads")=true, py::arg("nx")=10, py::arg("ny")=10, py::arg("flip_triangles")=false, py::arg("bbbpts")=py::list(), py::arg("bbbnames")=py::list(), py::arg("hppts")=py::list(), py::arg("hpbnd")=py::list()) ; ; diff --git a/libsrc/meshing/surfacegeom.cpp b/libsrc/meshing/surfacegeom.cpp index 40d272a8..14a265d3 100644 --- a/libsrc/meshing/surfacegeom.cpp +++ b/libsrc/meshing/surfacegeom.cpp @@ -45,10 +45,10 @@ namespace netgen prr = p[1]+2*eps; pll = p[1]-2*eps; - dr = GetTangentVectors(u, pr); - dl = GetTangentVectors(u, pl); - drr = GetTangentVectors(u, prr); - dll = GetTangentVectors(u, pll); + GetTangentVectors(u, pr, dr); + GetTangentVectors(u, pl, dl); + GetTangentVectors(u, prr, drr); + GetTangentVectors(u, pll, dll); f_vv = (1.0/(12.0*eps)) * (8.0*dr[1]-8.0*dl[1]-drr[1]+dll[1]); } @@ -74,11 +74,31 @@ namespace netgen return tang; } + void SurfaceGeometry :: GetTangentVectors(double u, double v, Array>& tang) const + { + + Point<2> pru = Point<2>(u+eps,v); + Point<2> plu = Point<2>(u-eps,v); + Point<2> prru = Point<2>(u+2*eps,v); + Point<2> pllu = Point<2>(u-2*eps,v); + + Point<2> prv = Point<2>(u,v+eps); + Point<2> plv = Point<2>(u,v-eps); + Point<2> prrv = Point<2>(u,v+2*eps); + Point<2> pllv = Point<2>(u,v-2*eps); + + + tang[0] = 1/(12.0*eps)*( 8.0*func(pru) - 8.0*func(plu) - func(prru) + func(pllu) ); + tang[1] = 1/(12.0*eps)*( 8.0*func(prv) - 8.0*func(plv) - func(prrv) + func(pllv) ); + } + + Vec<3> SurfaceGeometry :: GetNormal(int surfind, const Point<3> & p, const PointGeomInfo* gi) const { Array> tang = GetTangentVectors(gi->u, gi->v); auto normal = Cross(tang[0], tang[1]); - return Cross(tang[0], tang[1]); + normal.Normalize(); + return normal; } @@ -97,14 +117,13 @@ namespace netgen bool SurfaceGeometry :: ProjectPointGI (int surfind, Point<3> & p, PointGeomInfo & gi) const { - Array> tangs; + Array> tangs(2); Vec<3> diff, f_uu, f_vv, f_uv; Vec<2> r, dx; - double norm_r, det, energy=0.0, new_energy=0.0, alpha=2.0,u=0.0,v=0.0; + double norm_r, det, energy=0.0, new_energy=0.0, alpha=2.0,u=0.0,v=0.0,maxerr=1e-16; Mat<2,2> mat, inv; - int num=0, maxit=20; - double damping=0.2; - + int num=0, maxit=25; + double damping=0.5; //Solve minimization problem // argmin_(u,v) 0.5*\| f(u,v)-p\|^2 @@ -115,7 +134,7 @@ namespace netgen do { num++; - tangs = GetTangentVectors(gi.u, gi.v); + GetTangentVectors(gi.u, gi.v,tangs); diff = func(Point<2>(gi.u, gi.v)) - Vec<3>(p); energy = diff.Length2(); r = Vec<2>( diff*tangs[0], diff*tangs[1] ); @@ -146,12 +165,13 @@ namespace netgen while (alpha > 1e-10 && new_energy > energy+1e-14); if (alpha <= 1e-10) throw Exception("In SurfaceGeometry::ProjectPointGI: Linesearch min alpha reached!"); + gi.u = u; gi.v = v; } - while ( norm_r > 1e-12 && num < maxit); + while ( norm_r > maxerr && num < maxit); //Stay in reference domain [0,1]^2 if (gi.u < 0 || gi.u > 1 || gi.v < 0 || gi.v > 1) @@ -179,19 +199,13 @@ namespace netgen void SurfaceGeometry :: PointBetweenEdge(const Point<3> & p1, const Point<3> & p2, double secpoint, int surfi1, int surfi2, const EdgePointGeomInfo & ap1, const EdgePointGeomInfo & ap2, Point<3> & newp, EdgePointGeomInfo & newgi) const { - newp = p1+secpoint*(p2-p1); - - PointGeomInfo pgi; - pgi.u = ap1.u+secpoint*(ap2.u-ap1.u); - pgi.v = ap1.v+secpoint*(ap2.v-ap1.v); - - ProjectPointGI(surfi1, newp, pgi); - - newgi.u = pgi.u; - newgi.v = pgi.v; + newgi.u = ap1.u+secpoint*(ap2.u-ap1.u); + newgi.v = ap1.v+secpoint*(ap2.v-ap1.v); newgi.edgenr = ap1.edgenr; newgi.body = -1; newgi.dist = -1.0; + + newp = Point<3>(func(Point<2>(newgi.u, newgi.v))); } void SurfaceGeometry :: PointBetween(const Point<3> & p1, const Point<3> & p2, double secpoint, @@ -200,16 +214,16 @@ namespace netgen const PointGeomInfo & gi2, Point<3> & newp, PointGeomInfo & newgi) const { - newp = p1+secpoint*(p2-p1); - newgi.u = gi1.u+secpoint*(gi2.u-gi1.u); newgi.v = gi1.v+secpoint*(gi2.v-gi1.v); newgi.trignum = -1; - ProjectPointGI(surfi, newp, newgi); + newp = Point<3>(func(Point<2>(newgi.u, newgi.v))); + //newp = p1+secpoint*(p2-p1); + //ProjectPointGI(surfi, newp, newgi); } - int SurfaceGeometry :: GenerateMesh(shared_ptr & mesh, bool quads, int nx, int ny, bool flip_triangles, const Array>& bbbpts, const Array& bbbnames) + int SurfaceGeometry :: GenerateMesh(shared_ptr & mesh, bool quads, int nx, int ny, bool flip_triangles, const Array>& bbbpts, const Array& bbbnames, const Array>& hppoints, const Array& hpptsfac, const Array& hpbnd, const Array& hpbndfac) { mesh->SetDimension(3); @@ -241,6 +255,16 @@ namespace netgen indbbbpts[k] = pids[pids.Size()-1]; } } + + for (int k = 0; k < hppoints.Size(); k++) + { + auto diff = pnt - hppoints[k]; + if(diff.Length2() < 1e-14) + { + (*mesh)[pids[pids.Size()-1]].Singularity(hpptsfac[k]); + } + + } } for (bool f : found) @@ -318,8 +342,19 @@ namespace netgen Segment seg; seg.si = 1; seg.edgenr = 1; - seg.epgeominfo[0].edgenr = 1; - seg.epgeominfo[1].edgenr = 1; + seg.epgeominfo[0].edgenr = 0; + seg.epgeominfo[1].edgenr = 0; + //for hp refinement + seg.singedge_left = 0; + seg.singedge_right = 0; + for (size_t i=0; i < hpbnd.Size(); i++) + { + if (hpbnd[i] == "bottom") + { + seg.singedge_left = hpbndfac[i]; + seg.singedge_right = hpbndfac[i]; + } + } // needed for codim2 in 3d seg.edgenr = 1; for(int i=0; i < nx; i++) @@ -341,6 +376,18 @@ namespace netgen seg.si = 2; seg.edgenr = 2; + seg.singedge_left = 0; + seg.singedge_right = 0; + + for (size_t i=0; i < hpbnd.Size(); i++) + { + if (hpbnd[i] == "right") + { + seg.singedge_left = hpbndfac[i]; + seg.singedge_right = hpbndfac[i]; + } + } + for(int i=0; i> GetTangentVectors(double u, double v) const; + void GetTangentVectors(double u, double v, Array>& tang) const; + + virtual Vec<3> GetNormal(int surfind, const Point<3> & p, const PointGeomInfo* gi) const override; virtual PointGeomInfo ProjectPoint(int surfind, Point<3> & p) const override; @@ -59,7 +62,7 @@ namespace netgen const PointGeomInfo & gi2, Point<3> & newp, PointGeomInfo & newgi) const override; - int GenerateMesh(shared_ptr & mesh, bool quads, int nx, int ny, bool flip_triangles, const Array>& bbbpts, const Array& bbbnames); + int GenerateMesh(shared_ptr & mesh, bool quads, int nx, int ny, bool flip_triangles, const Array>& bbbpts, const Array& bbbnames, const Array>& hppoints, const Array& hpptsfac, const Array& hpbnd, const Array& hpbndfac); }; From 10c0fd350a5b6f3e570c3f7e0b7ee72a411ddaca Mon Sep 17 00:00:00 2001 From: Michael Date: Fri, 30 Oct 2020 15:28:00 +0100 Subject: [PATCH 238/384] save/load pointelements --- libsrc/meshing/meshclass.cpp | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/libsrc/meshing/meshclass.cpp b/libsrc/meshing/meshclass.cpp index 572547b9..85b37419 100644 --- a/libsrc/meshing/meshclass.cpp +++ b/libsrc/meshing/meshclass.cpp @@ -602,7 +602,20 @@ namespace netgen outfile << (*this)[pi](1)/scale << " "; outfile.width(22); outfile << (*this)[pi](2)/scale << "\n"; - } + } + + outfile << "\n" << "\n"; + outfile << "# pnum index" << "\n"; + outfile << "pointelements" << "\n"; + outfile << pointelements.Size() << "\n"; + + for (i = 0; i < pointelements.Size(); i++) + { + outfile.width(8); + outfile << pointelements[i].pnum << " "; + outfile.width(8); + outfile << pointelements[i].index << "\n"; + } if (ident -> GetMaxNr() > 0) { @@ -1083,6 +1096,19 @@ namespace netgen PrintMessage (3, n, " points done"); } + if (strcmp (str, "pointelements") == 0) + { + infile >> n; + PrintMessage (3, n, " pointelements"); + for (i = 1; i <= n; i++) + { + Element0d el; + infile >> el.pnum >> el.index; + pointelements.Append (el); + } + PrintMessage (3, n, " pointelements done"); + } + if (strcmp (str, "identifications") == 0) { infile >> n; From 9578e4a41d8644703c00b7cfe52b5b10fa4720aa Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Tue, 3 Nov 2020 12:28:13 +0100 Subject: [PATCH 239/384] add project to boundary in boundarylayer and correctly treat inverse boundaries --- libsrc/meshing/boundarylayer.cpp | 54 ++++++++++++++++++++---------- libsrc/meshing/boundarylayer.hpp | 1 + libsrc/meshing/python_mesh.cpp | 21 ++++++++++-- tests/pytest/test_boundarylayer.py | 25 +++++++++++++- 4 files changed, 79 insertions(+), 22 deletions(-) diff --git a/libsrc/meshing/boundarylayer.cpp b/libsrc/meshing/boundarylayer.cpp index 710251a6..81c466a8 100644 --- a/libsrc/meshing/boundarylayer.cpp +++ b/libsrc/meshing/boundarylayer.cpp @@ -215,6 +215,11 @@ namespace netgen if (blp.surfid.Contains(sel.GetIndex())) { auto n2 = GetSurfaceNormal(mesh,sel); + auto& fd = mesh.GetFaceDescriptor(sel.GetIndex()); + auto domin = fd.DomainIn(); + auto domout = fd.DomainOut(); + if(blp.domains.Test(domout) && !blp.domains.Test(domin)) + n2 *= -1; if(!blp.outside) n2 *= -1; for(auto pi : sel.PNums()) @@ -238,24 +243,37 @@ namespace netgen } // project growthvector on surface for inner angles - // for(const auto& sel : mesh.SurfaceElements()) - // if(!blp.surfid.Contains(sel.GetIndex())) - // { - // auto n = GetSurfaceNormal(mesh, sel); - // for(auto pi : sel.PNums()) - // { - // if(growthvectors[pi].Length2() == 0.) - // continue; - // auto& g = growthvectors[pi]; - // auto ng = n * g; - // auto gg = g * g; - // auto nn = n * n; - // if(fabs(ng*ng-nn*gg) < 1e-12 || fabs(ng) < 1e-12) continue; - // auto a = -ng*ng/(ng*ng-nn * gg); - // auto b = ng*gg/(ng*ng-nn*gg); - // g += a*g + b*n; - // } - // } + for(const auto& sel : mesh.SurfaceElements()) + // if(!blp.surfid.Contains(sel.GetIndex())) + // { + if(blp.project_boundaries.Contains(sel.GetIndex())) + { + auto n = GetSurfaceNormal(mesh, sel); + for(auto i : Range(sel.PNums())) + { + auto pi = sel.PNums()[i]; + if(growthvectors[pi].Length2() == 0.) + continue; + auto next = sel.PNums()[(i+1)%sel.GetNV()]; + auto prev = sel.PNums()[i == 0 ? sel.GetNV()-1 : i-1]; + auto v1 = (mesh[next] - mesh[pi]).Normalize(); + auto v2 = (mesh[prev] - mesh[pi]).Normalize(); + auto v3 = growthvectors[pi]; + v3.Normalize(); + // only project if sel goes in boundarylayer direction + if((v1 * v3 < 1e-12) || (v2 * v3 < 1e-12)) + continue; + + auto& g = growthvectors[pi]; + auto ng = n * g; + auto gg = g * g; + auto nn = n * n; + if(fabs(ng*ng-nn*gg) < 1e-12 || fabs(ng) < 1e-12) continue; + auto a = -ng*ng/(ng*ng-nn * gg); + auto b = ng*gg/(ng*ng-nn*gg); + g += a*g + b*n; + } + } if (!blp.grow_edges) { diff --git a/libsrc/meshing/boundarylayer.hpp b/libsrc/meshing/boundarylayer.hpp index 404f648a..113d9b1f 100644 --- a/libsrc/meshing/boundarylayer.hpp +++ b/libsrc/meshing/boundarylayer.hpp @@ -18,6 +18,7 @@ public: BitArray domains; bool outside = false; // set the boundary layer on the outside bool grow_edges = false; + Array project_boundaries; }; DLL_HEADER void GenerateBoundaryLayer (Mesh & mesh, diff --git a/libsrc/meshing/python_mesh.cpp b/libsrc/meshing/python_mesh.cpp index c1cbb0c5..2dba11ea 100644 --- a/libsrc/meshing/python_mesh.cpp +++ b/libsrc/meshing/python_mesh.cpp @@ -833,6 +833,7 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m) .def("FaceDescriptor", static_cast (&Mesh::GetFaceDescriptor), py::return_value_policy::reference) .def("GetNFaceDescriptors", &Mesh::GetNFD) + .def("GetNDomains", &Mesh::GetNDomains) .def("GetVolumeNeighboursOfSurfaceElement", [](Mesh & self, size_t sel) { @@ -1012,7 +1013,8 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m) variant thickness, variant material, variant domain, bool outside, - bool grow_edges) + bool grow_edges, + optional project_boundaries) { BoundaryLayerParameters blp; if(int* bc = get_if(&boundary); bc) @@ -1034,7 +1036,7 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m) if(dom_pattern) { regex pattern(*dom_pattern); - if(regex_match(self.GetMaterial(fd.DomainIn()), pattern) || (fd.DomainOut() > 0 ? regex_match(self.GetMaterial(fd.DomainOut()), pattern) : false)) + if((fd.DomainIn() > 0 && regex_match(self.GetMaterial(fd.DomainIn()), pattern)) || (fd.DomainOut() > 0 && regex_match(self.GetMaterial(fd.DomainOut()), pattern))) blp.surfid.Append(i); } else @@ -1043,6 +1045,14 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m) } } + if(project_boundaries.has_value()) + { + regex pattern(*project_boundaries); + for(int i = 1; i<=self.GetNFD(); i++) + if(regex_match(self.GetFaceDescriptor(i).GetBCName(), pattern)) + blp.project_boundaries.Append(i); + } + if(double* pthickness = get_if(&thickness); pthickness) { blp.heights.Append(*pthickness); @@ -1102,7 +1112,7 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m) self.UpdateTopology(); }, py::arg("boundary"), py::arg("thickness"), py::arg("material"), py::arg("domains") = ".*", py::arg("outside") = false, - py::arg("grow_edges") = false, + py::arg("grow_edges") = false, py::arg("project_boundaries")=nullopt, R"delimiter( Add boundary layer to mesh. @@ -1127,6 +1137,11 @@ outside : bool = False grow_edges : bool = False Grow boundary layer over edges. +project_boundaries : Optional[str] = None + Project boundarylayer to these boundaries if they meet them. Set + to boundaries that meet boundarylayer at a non-orthogonal edge and + layer-ending should be projected to that boundary. + )delimiter") .def ("EnableTable", [] (Mesh & self, string name, bool set) diff --git a/tests/pytest/test_boundarylayer.py b/tests/pytest/test_boundarylayer.py index 733aa0dc..02cba2f8 100644 --- a/tests/pytest/test_boundarylayer.py +++ b/tests/pytest/test_boundarylayer.py @@ -54,6 +54,29 @@ def test_boundarylayer2(outside, version, capfd): mesh = geo.GenerateMesh() should_ne = mesh.ne + 2 * GetNSurfaceElements(mesh, ["default"], "part") layersize = 0.05 - mesh.BoundaryLayer("default", [0.5 * layersize, layersize], "layer", domains="part", outside=outside, grow_edges=True) + mesh.BoundaryLayer("default", [0.5 * layersize, layersize], "part", domains="part", outside=outside, grow_edges=True) assert mesh.ne == should_ne assert not "elements are not matching" in capfd.readouterr().out + import netgen.gui + ngs = pytest.importorskip("ngsolve") + ngs.Draw(ngs.Mesh(mesh)) + mesh = ngs.Mesh(mesh) + assert ngs.Integrate(1, mesh.Materials("part")) == pytest.approx(0.5*2.05*2.05 if outside else 0.4*2*2) + assert ngs.Integrate(1, mesh) == pytest.approx(3**3) + + +@pytest.mark.parametrize("outside", [True, False]) +def test_wrong_orientation(outside): + geo = CSGeometry() + brick = OrthoBrick((-1,0,0),(1,1,1)) - Plane((0,0,0), (1,0,0)) + geo.Add(brick.mat("air")) + + mesh = geo.GenerateMesh() + + mesh.BoundaryLayer(".*", 0.1, "air", domains="air", outside=outside, + grow_edges=True) + ngs = pytest.importorskip("ngsolve") + mesh = ngs.Mesh(mesh) + assert ngs.Integrate(1, mesh) == pytest.approx(1.2**3 if outside else 1) + + From 3dec7c447e666378813fe398e43e4455758cb111 Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Tue, 3 Nov 2020 17:29:58 +0100 Subject: [PATCH 240/384] map segment si as well, not only surface element index --- libsrc/meshing/meshclass.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libsrc/meshing/meshclass.cpp b/libsrc/meshing/meshclass.cpp index e21f81e1..66d28355 100644 --- a/libsrc/meshing/meshclass.cpp +++ b/libsrc/meshing/meshclass.cpp @@ -5919,6 +5919,12 @@ namespace netgen SurfaceElement(els_of_face[i]).next = facedecoding[ind-1].firstelement; facedecoding[ind-1].firstelement = els_of_face[i]; } + + // map the segments + for(auto& seg : segments) + if(!usedp.Test(seg[0]) || !usedp.Test(seg[1])) + if(seg.si == fdi) + seg.si = nface; } fdi++; From 37ae505d5a91506f371752e13b2e01c423e33464 Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Tue, 3 Nov 2020 17:29:58 +0100 Subject: [PATCH 241/384] map segment si as well, not only surface element index --- libsrc/meshing/meshclass.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libsrc/meshing/meshclass.cpp b/libsrc/meshing/meshclass.cpp index e21f81e1..66d28355 100644 --- a/libsrc/meshing/meshclass.cpp +++ b/libsrc/meshing/meshclass.cpp @@ -5919,6 +5919,12 @@ namespace netgen SurfaceElement(els_of_face[i]).next = facedecoding[ind-1].firstelement; facedecoding[ind-1].firstelement = els_of_face[i]; } + + // map the segments + for(auto& seg : segments) + if(!usedp.Test(seg[0]) || !usedp.Test(seg[1])) + if(seg.si == fdi) + seg.si = nface; } fdi++; From 45059fa7afb42bcae3f3ab34c5d9b842ce289226 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Tue, 3 Nov 2020 18:41:09 +0100 Subject: [PATCH 242/384] csg2d - fix CleanupResult Check for more edge properties (maxh, bc etc.) before removing "intermediate" and unnecessary vertices --- libsrc/geom2d/csg2d.cpp | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/libsrc/geom2d/csg2d.cpp b/libsrc/geom2d/csg2d.cpp index f5f85ea7..a96986b8 100644 --- a/libsrc/geom2d/csg2d.cpp +++ b/libsrc/geom2d/csg2d.cpp @@ -1292,20 +1292,38 @@ void CreateResult(Solid2d & sp, Solid2d & sr, bool UNION) } } +// Check if vertex v is not necessary (i.e. is on the line v->prev, v->next and has same info as v->prev and no pinfo +bool canRemoveVertex( Vertex * v ) +{ + return false; + if(v->spline) + return false; + if(v->pinfo.name != POINT_NAME_DEFAULT) + return false; + if(v->pinfo.maxh != MAXH_DEFAULT) + return false; + + if(v->info.bc != v->prev->info.bc || v->info.maxh != v->prev->info.maxh ) + return false; + + if(fabs(Area(*v->prev,*v,*v->next)) >= EPSILON) + return false; + + return true; +} + void CleanUpResult(Solid2d & sr) { auto & RR = sr.polys; for (Loop& R : RR) { - while ( (R.first.get() != NULL) && (fabs(Area(*R.first->prev,*R.first,*R.first->next)) < EPSILON) ) + while ( (R.first.get() != NULL) && canRemoveVertex(R.first.get())) R.Remove(R.first.get()); if (R.first.get() != NULL) for (Vertex* V : R.Vertices(ALL)) - if (!V->spline && !V->prev->spline && fabs(Area(*V->prev,*V,*V->next)) < EPSILON) - { + if (canRemoveVertex(V)) R.Remove(V); - } } for (int i = RR.Size()-1; i>=0; i--) if(RR[i].Size()==0) From 8b14f399c1455e489a08fdef5ecd9fd3ab445eec Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Tue, 3 Nov 2020 18:42:04 +0100 Subject: [PATCH 243/384] csg2d - fix bug in getNonIntersectionVertex() If a loop has no non-intersecting vertex, a new one is inserted -> set all vertex properties correctly (info, spline) --- libsrc/geom2d/csg2d.cpp | 33 +++++++++++++++++++++++++++++++++ libsrc/geom2d/csg2d.hpp | 26 +++++--------------------- 2 files changed, 38 insertions(+), 21 deletions(-) diff --git a/libsrc/geom2d/csg2d.cpp b/libsrc/geom2d/csg2d.cpp index a96986b8..01e20981 100644 --- a/libsrc/geom2d/csg2d.cpp +++ b/libsrc/geom2d/csg2d.cpp @@ -1565,6 +1565,39 @@ Solid2d ClipSolids ( Solid2d && s1, Solid2d && s2, char op) return std::move(res); } +Vertex* Loop :: getNonIntersectionVertex() + { + for (Vertex* v : Vertices(ALL)) + if (!v->is_intersection) + return(v); + + // no non-intersection vertex found -> generate and return temporary vertex + for (Vertex* v : Vertices(ALL)) + // make sure that edge from V to V->next is not collinear with other polygon + if ( (v->next->neighbour != v->neighbour->prev) && (v->next->neighbour != v->neighbour->next) ) + { + // add edge midpoint as temporary vertex + if(v->spline) + { + auto p = v->spline->GetPoint(0.5); + auto s = *v->spline; + v->spline = Split(s, 0, 0.5); + auto vnew = v->Insert(p); + vnew->info = v->info; + vnew->spline = Split(s, 0.5, 1.0); + return vnew; + } + else + { + auto p = Center(*v, *v->next); + auto vnew = v->Insert(p); + vnew->info = v->info; + return vnew; + } + } + return(NULL); + } + bool Loop :: IsInside( Point<2> r ) const { int w = 0; diff --git a/libsrc/geom2d/csg2d.hpp b/libsrc/geom2d/csg2d.hpp index 118060f8..42c44a89 100644 --- a/libsrc/geom2d/csg2d.hpp +++ b/libsrc/geom2d/csg2d.hpp @@ -29,10 +29,10 @@ enum IntersectionType T_INTERSECTION_Q, T_INTERSECTION_P, V_INTERSECTION, - X_OVERLAP, - T_OVERLAP_Q, - T_OVERLAP_P, - V_OVERLAP + X_OVERLAP, // Q0 -- P1 -- Q1 -- P0 (different direction) + T_OVERLAP_Q, // same direction or P inside Q + T_OVERLAP_P, // same direction or Q inside P + V_OVERLAP // one common point }; enum IntersectionLabel @@ -588,23 +588,7 @@ struct Loop // // return and insert a non-intersection vertex // - Vertex* getNonIntersectionVertex() - { - for (Vertex* v : Vertices(ALL)) - if (!v->is_intersection) - return(v); - - // no non-intersection vertex found -> generate and return temporary vertex - for (Vertex* v : Vertices(ALL)) - // make sure that edge from V to V->next is not collinear with other polygon - if ( (v->next->neighbour != v->neighbour->prev) && (v->next->neighbour != v->neighbour->next) ) - { - // add edge midpoint as temporary vertex - auto p = Center(*v, *v->next); - return v->Insert(p); - } - return(NULL); - } + Vertex* getNonIntersectionVertex(); void SetBC(string bc) { From ffb98ee68f5d55ffa62aac84dbf3fb6a6a094f91 Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Tue, 3 Nov 2020 21:59:32 +0100 Subject: [PATCH 244/384] add test for boundarylayers on splitted surfaces --- tests/pytest/test_boundarylayer.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/pytest/test_boundarylayer.py b/tests/pytest/test_boundarylayer.py index 02cba2f8..27124613 100644 --- a/tests/pytest/test_boundarylayer.py +++ b/tests/pytest/test_boundarylayer.py @@ -79,4 +79,18 @@ def test_wrong_orientation(outside): mesh = ngs.Mesh(mesh) assert ngs.Integrate(1, mesh) == pytest.approx(1.2**3 if outside else 1) +def test_splitted_surface(): + geo = CSGeometry() + brick = OrthoBrick((0,0,0), (1,1,1)) + slots = OrthoBrick((0.2,0,-1), (0.4, 1, 2)) + OrthoBrick((0.6, 0,-1), (0.8, 1,2)) + geo.Add((brick-slots).mat("block")) + geo.Add((brick*slots).mat("slot")) + + mesh = geo.GenerateMesh() + mesh.BoundaryLayer(".*", [0.001, 0.002], "block", "block", outside=False, + grow_edges=True) + ngs = pytest.importorskip("ngsolve") + mesh = ngs.Mesh(mesh) + assert ngs.Integrate(1, mesh) == pytest.approx(1) + assert ngs.Integrate(1, mesh.Materials("slot")) == pytest.approx(0.4) From 6199c7f66b0777a05f79a117c6875598af11138c Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Thu, 5 Nov 2020 14:59:58 +0100 Subject: [PATCH 245/384] csg2d interface --- libsrc/geom2d/csg2d.cpp | 15 +++++++++------ libsrc/geom2d/csg2d.hpp | 5 +++-- libsrc/geom2d/python_geom2d.cpp | 13 +++---------- libsrc/meshing/python_mesh.cpp | 6 ++++++ 4 files changed, 21 insertions(+), 18 deletions(-) diff --git a/libsrc/geom2d/csg2d.cpp b/libsrc/geom2d/csg2d.cpp index 01e20981..fe0c8bd0 100644 --- a/libsrc/geom2d/csg2d.cpp +++ b/libsrc/geom2d/csg2d.cpp @@ -1703,11 +1703,14 @@ Solid2d & Solid2d :: Move( Vec<2> v ) return Transform( [v](Point<2> p) -> Point<2> { return p+v; } ); } -Solid2d & Solid2d :: Scale( double sx, double sy ) +Solid2d & Solid2d :: Scale( double s ) { - if(sy==0.0) - sy=sx; - return Transform( [sx,sy](Point<2> p) -> Point<2> { return{p[0]*sx, p[1]*sy}; } ); + return Transform( [s](Point<2> p) -> Point<2> { return{p[0]*s, p[1]*s}; } ); +} + +Solid2d & Solid2d :: Scale( Vec<2> s ) +{ + return Transform( [s](Point<2> p) -> Point<2> { return{p[0]*s[0], p[1]*s[1]}; } ); } Solid2d & Solid2d :: RotateRad( double ang, Point<2> center ) @@ -1720,8 +1723,8 @@ Solid2d & Solid2d :: RotateRad( double ang, Point<2> center ) p -= c; double x = p[0]; double y = p[1]; - p[0] = cosa*x+sina*y; - p[1] = -sina*x+cosa*y; + p[0] = cosa*x-sina*y; + p[1] = sina*x+cosa*y; p += c; return p; } ); diff --git a/libsrc/geom2d/csg2d.hpp b/libsrc/geom2d/csg2d.hpp index 42c44a89..afc1e654 100644 --- a/libsrc/geom2d/csg2d.hpp +++ b/libsrc/geom2d/csg2d.hpp @@ -678,11 +678,12 @@ struct Solid2d } Solid2d & Move( Vec<2> v ); - Solid2d & Scale( double sx, double sy=0.0 ); + Solid2d & Scale( double s ); + Solid2d & Scale( Vec<2> s ); Solid2d & RotateRad( double ang, Point<2> center = {0,0} ); Solid2d & RotateDeg( double ang, Point<2> center = {0,0} ) { - return RotateRad( ang/180.*M_PI ); + return RotateRad( ang/180.*M_PI, center ); } Solid2d & BC(string bc) diff --git a/libsrc/geom2d/python_geom2d.cpp b/libsrc/geom2d/python_geom2d.cpp index b8f5a871..03f57398 100644 --- a/libsrc/geom2d/python_geom2d.cpp +++ b/libsrc/geom2d/python_geom2d.cpp @@ -414,16 +414,9 @@ DLL_HEADER void ExportGeom2d(py::module &m) .def("Copy", [](Solid2d & self) -> Solid2d { return self; }) .def("Move", &Solid2d::Move) - .def("Scale", &Solid2d::Scale) - .def("Rotate", [](Solid2d & self, optional rad, optional deg, Point<2> center ) - { - if(rad) - self.RotateRad(*rad, center); - if(deg) - self.RotateDeg(*deg, center); - return self; - }, py::arg("rad")=nullopt, py::arg("deg")=nullopt, py::arg("center")=Point<2>{0,0}) - + .def("Scale", static_cast(&Solid2d::Scale)) + .def("Scale", static_cast)>(&Solid2d::Scale)) + .def("Rotate", &Solid2d::RotateDeg, py::arg("angle"), py::arg("center")=Point<2>{0,0}) ; diff --git a/libsrc/meshing/python_mesh.cpp b/libsrc/meshing/python_mesh.cpp index c1cbb0c5..968c4cd7 100644 --- a/libsrc/meshing/python_mesh.cpp +++ b/libsrc/meshing/python_mesh.cpp @@ -211,6 +211,10 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m) py::class_> (m, "Vec2d") .def(py::init()) + .def(py::init( [] (std::pair xy) + { + return Vec<2>{xy.first, xy.second}; + })) .def ("__str__", &ToString>) .def(py::self==py::self) .def(py::self+py::self) @@ -223,6 +227,8 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m) .def("__len__", [](Vec<2>& /*unused*/) { return 2; }) ; + py::implicitly_convertible>(); + py::class_> (m, "Vec3d") .def(py::init()) .def(py::init([](py::tuple v) From dae6ded752fd245eda6c6c8b17b2be02d24c52fc Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Fri, 6 Nov 2020 11:51:15 +0100 Subject: [PATCH 246/384] fix test (csg2d interface change) --- tests/pytest/test_csg2d.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/pytest/test_csg2d.py b/tests/pytest/test_csg2d.py index d962085c..06e875a9 100644 --- a/tests/pytest/test_csg2d.py +++ b/tests/pytest/test_csg2d.py @@ -5,7 +5,7 @@ from pytest import approx def test_two_circles(): c1 = Circle(center=(0,0), radius=1) - c2 = c1.Rotate(deg=45) + c2 = c1.Rotate(45) s = c1*c2 geo = CSG2d() geo.Add(s) From de760692837abc5191f3653b07a51bcc52bc32f8 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Wed, 11 Nov 2020 15:56:56 +0100 Subject: [PATCH 247/384] CSG2d bugfix Fixes bug in IsInside(p) test for splines if p lies on an edge of the surrounding triangle. Do a fast check using (new) function IsCloseToTrig() instead of IsInsideTrig(). --- libsrc/geom2d/csg2d.cpp | 8 +++++++- tests/pytest/test_csg2d.py | 29 +++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/libsrc/geom2d/csg2d.cpp b/libsrc/geom2d/csg2d.cpp index fe0c8bd0..f97a0633 100644 --- a/libsrc/geom2d/csg2d.cpp +++ b/libsrc/geom2d/csg2d.cpp @@ -402,6 +402,12 @@ bool IsInsideTrig( const array,3> & t, Point<2> r ) return ( (w % 2) != 0 ); } +bool IsCloseToTrig( const array,3> & t, Point<2> r, double eps=1e-4 ) +{ + r += eps * (Center(t[0], t[1], t[2])-r); // move point a bit to center of trig + return IsInsideTrig( t, r ); +} + IntersectionType IntersectTrig( Point<2> p0, Point<2> p1, const array,3> & trig) { @@ -1612,7 +1618,7 @@ bool Loop :: IsInside( Point<2> r ) const auto s0 = s.StartPI(); auto s1 = s.TangentPoint(); auto s2 = s.EndPI(); - if(!IsInsideTrig( {s0, s1, s2} , r )) + if(!IsCloseToTrig( {s0, s1, s2} , r )) w += w_simple; else { diff --git a/tests/pytest/test_csg2d.py b/tests/pytest/test_csg2d.py index 06e875a9..204e8ce1 100644 --- a/tests/pytest/test_csg2d.py +++ b/tests/pytest/test_csg2d.py @@ -54,6 +54,35 @@ def test_trig_and_circle(): ngs.Draw(mesh) +def test_circle_plus_rect(): + circle = Circle( center=(0,0), radius=1 ) + rect = Rectangle( pmin=(-0.5,0.0), pmax=(0.5,0.5) ) + + geo = CSG2d() + geo.Add(circle+rect) + m = geo.GenerateMesh(maxh=0.2) + + + ngs = pytest.importorskip("ngsolve") + mesh = ngs.Mesh(m) + mesh.Curve(5) + assert ngs.Integrate(1.0, mesh) == approx(math.pi) + +def test_circle_plus_rect1(): + circle = Circle( center=(0,0), radius=1 ) + rect = Rectangle( pmin=(-0.5,-0.5), pmax=(0.5,0.5) ) + + geo = CSG2d() + geo.Add(circle+rect) + m = geo.GenerateMesh(maxh=0.2) + + + ngs = pytest.importorskip("ngsolve") + mesh = ngs.Mesh(m) + mesh.Curve(5) + assert ngs.Integrate(1.0, mesh) == approx(math.pi) + + if __name__ == "__main__": test_two_circles() test_two_edge() From 870b1479264afa9abd455dbd323ba075790be9ff Mon Sep 17 00:00:00 2001 From: Michael Neunteufel Date: Wed, 11 Nov 2020 16:40:06 +0000 Subject: [PATCH 248/384] add ellipse as csg2d solid object --- python/geom2d.py | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/python/geom2d.py b/python/geom2d.py index 886bfb60..3bd69d14 100644 --- a/python/geom2d.py +++ b/python/geom2d.py @@ -1,5 +1,6 @@ from .libngpy._geom2d import SplineGeometry, Solid2d, CSG2d, Rectangle, Circle, EdgeInfo, PointInfo from .meshing import meshsize +import math as math unit_square = SplineGeometry() _pnts = [ (0,0), (1,0), (1,1), (0,1) ] @@ -144,3 +145,34 @@ def cp(p_or_px, py_or_none = None): return EdgeInfo(control_point=p) else: return EdgeInfo(control_point=(p_or_px,py_or_none)) + + +def Ellipse(center, a, b, bc="ellipse", mat="ellipse"): + """Creates ellipse centered at point center with principle axis a and b. + + Parameters + --------- + center : Vec2 + center of ellipse + a : Vec2 + first principle axis, needs to be perpendicular to b + b : Vec2 + second principle axis, needs to be perpendicular to a + bc : string + boundary name + mat : string + material name + """ + if abs(a[0]*b[0] + a[1]*b[1]) > 1e-12: + raise Exception("In Ellipse: principle axis a and b are not perpendicular") + + ellipse = Circle( center=(0,0), radius=1.0, mat=mat, bc=bc ) + + alpha = math.pi/2-math.atan2(a[0],a[1]) + r_a = math.sqrt(a[0]**2+a[1]**2) + r_b = math.sqrt(b[0]**2+b[1]**2) + ellipse.Scale( (r_a,r_b) ) + ellipse.Rotate( alpha/math.pi*180, center=(0,0) ) + ellipse.Move( center ) + + return ellipse From 22d6303c5c1025b849d23aacf82a4bcfd48e43b8 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Fri, 13 Nov 2020 16:09:59 +0100 Subject: [PATCH 249/384] bugfix in csg2d handle degenerate quadratic equation in intersection of spline and segment correctly --- libsrc/geom2d/csg2d.cpp | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/libsrc/geom2d/csg2d.cpp b/libsrc/geom2d/csg2d.cpp index f97a0633..09f743b7 100644 --- a/libsrc/geom2d/csg2d.cpp +++ b/libsrc/geom2d/csg2d.cpp @@ -250,13 +250,20 @@ IntersectionType IntersectSplineSegment( const Spline & s, const Point<2> & r0, double det = b_*b_ - 4*a_*c_; if(det<0.0) return NO_INTERSECTION; - double sqrt_det = sqrt(det); - double t1 = 1.0/(2*a_) * (-b_ + sqrt_det); - double t2 = 1.0/(2*a_) * (-b_ - sqrt_det); - double t = min(t1,t2); - if(tEPSILON) + { + double sqrt_det = sqrt(det); + double t1 = 1.0/(2*a_) * (-b_ + sqrt_det); + double t2 = 1.0/(2*a_) * (-b_ - sqrt_det); + t = min(t1, t2); + if(t & r0, double det = b_*b_ - 4*a_*c_; if(det<0.0) return NO_INTERSECTION; + double sqrt_det = sqrt(det); double vbeta[2]; - vbeta[0] = 1.0/(2*a_) * (-b_ + sqrt_det); - vbeta[1] = 1.0/(2*a_) * (-b_ - sqrt_det); + + if(fabs(a_)>EPSILON) + { + vbeta[0] = 1.0/(2*a_) * (-b_ + sqrt_det); + vbeta[1] = 1.0/(2*a_) * (-b_ - sqrt_det); + } + else // degenrate quadratic equation + vbeta[0] = vbeta[1] = -c_/b_; int dim = fabs(vr[0]) > fabs(vr[1]) ? 0 : 1; double valpha[2]; From ee430a6e1e7a5c1875a5adbf32466199d2e670be Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Tue, 17 Nov 2020 15:24:44 +0100 Subject: [PATCH 250/384] use segmentindex as index for mesh.segments array --- libsrc/meshing/meshclass.hpp | 2 +- libsrc/meshing/meshtype.hpp | 6 +++++- libsrc/meshing/python_mesh.cpp | 4 ++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/libsrc/meshing/meshclass.hpp b/libsrc/meshing/meshclass.hpp index e3b45b9b..1de31c97 100644 --- a/libsrc/meshing/meshclass.hpp +++ b/libsrc/meshing/meshclass.hpp @@ -38,7 +38,7 @@ namespace netgen NgMPI_Comm comm; /// line-segments at edges - Array segments; + Array segments; /// surface elements, 2d-inner elements Array surfelements; /// volume elements diff --git a/libsrc/meshing/meshtype.hpp b/libsrc/meshing/meshtype.hpp index 2f49ad70..8644b6aa 100644 --- a/libsrc/meshing/meshtype.hpp +++ b/libsrc/meshing/meshtype.hpp @@ -306,13 +306,17 @@ namespace netgen SegmentIndex & operator= (const SegmentIndex & ai) { i = ai.i; return *this; } SegmentIndex & operator= (int ai) { i = ai; return *this; } - operator int () const { return i; } + constexpr operator int () const { return i; } SegmentIndex& operator++ () { ++i; return *this; } SegmentIndex& operator-- () { --i; return *this; } SegmentIndex operator++ (int) { return i++; } SegmentIndex operator-- (int) { return i--; } }; + inline void SetInvalid (SegmentIndex & id) { id = -1; } + inline bool IsInvalid (SegmentIndex & id) { return id == -1; } + + inline istream & operator>> (istream & ist, SegmentIndex & pi) { int i; ist >> i; pi = i; return ist; diff --git a/libsrc/meshing/python_mesh.cpp b/libsrc/meshing/python_mesh.cpp index fe1c6f8a..111cb4b9 100644 --- a/libsrc/meshing/python_mesh.cpp +++ b/libsrc/meshing/python_mesh.cpp @@ -603,7 +603,7 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m) ExportArray(m); ExportArray(m); - ExportArray(m); + ExportArray(m); ExportArray(m); ExportArray(m); ExportArray(m); @@ -823,7 +823,7 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m) py::return_value_policy::reference) .def("Elements1D", - static_cast&(Mesh::*)()> (&Mesh::LineSegments), + static_cast&(Mesh::*)()> (&Mesh::LineSegments), py::return_value_policy::reference) .def("Elements0D", FunctionPointer([] (Mesh & self) -> Array& From 609cbbcadfb23e90ff9a619ec22daa4b8dc4c0ad Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Tue, 17 Nov 2020 18:43:39 +0100 Subject: [PATCH 251/384] rewrite create boundarylayer function (now more efficient and stable and easier) --- libsrc/meshing/boundarylayer.cpp | 968 ++++++++++------------------- libsrc/meshing/boundarylayer.hpp | 2 +- libsrc/meshing/python_mesh.cpp | 39 +- tests/pytest/test_boundarylayer.py | 14 +- 4 files changed, 359 insertions(+), 664 deletions(-) diff --git a/libsrc/meshing/boundarylayer.cpp b/libsrc/meshing/boundarylayer.cpp index 81c466a8..63c90ba9 100644 --- a/libsrc/meshing/boundarylayer.cpp +++ b/libsrc/meshing/boundarylayer.cpp @@ -88,663 +88,385 @@ namespace netgen cout << "Quads: " << nq << endl; } + void GenerateBoundaryLayer(Mesh& mesh, const BoundaryLayerParameters& blp) + { + int max_edge_nr = -1; + for(const auto& seg : mesh.LineSegments()) + if(seg.edgenr > max_edge_nr) + max_edge_nr = seg.edgenr; + int new_mat_nr = mesh.GetNDomains() +1; + mesh.SetMaterial(new_mat_nr, blp.new_mat); + auto domains = blp.domains; + if(!blp.outside) + domains.Invert(); + mesh.UpdateTopology(); + auto& meshtopo = mesh.GetTopology(); -/* - Philippose Rajan - 11 June 2009 + int np = mesh.GetNP(); + int ne = mesh.GetNE(); + int nse = mesh.GetNSE(); + int nseg = mesh.GetNSeg(); - Function to calculate the surface normal at a given - vertex of a surface element, with respect to that - surface element. + Array, PointIndex> mapto(np); - This function is used by the boundary layer generation - function, in order to calculate the effective direction - in which the prismatic layer should grow -*/ - inline Vec<3> GetSurfaceNormal(Mesh & mesh, const Element2d & el) - { - auto v0 = mesh[el[0]]; - auto v1 = mesh[el[1]]; - auto v2 = mesh[el[2]]; - Vec<3> vec1 = v1-v0; - Vec<3> vec2 = v2-v0; - Vec<3> normal = Cross(vec1, vec2); - normal.Normalize(); - return normal; - } + Array, PointIndex> growthvectors(np); + growthvectors = 0.; -/* - Philippose Rajan - 11 June 2009 - modified by Christopher Lackner Apr 2020 - - Added an initial experimental function for - generating prismatic boundary layers on - a given set of surfaces. - - The number of layers, height of the first layer - and the growth / shrink factor can be specified - by the user + Array surfacefacs(mesh.GetNFD()+1); + surfacefacs = 0.; - Currently, the layer height is calculated using: - height = h_first_layer * (growth_factor^(num_layers - 1)) -*/ - void GenerateBoundaryLayer (Mesh & mesh, const BoundaryLayerParameters & blp) - { - PrintMessage(1, "Generating boundary layer..."); - PrintMessage(3, "Old NP: ", mesh.GetNP()); - PrintMessage(3, "Old NSE: ",mesh.GetNSE()); + auto getSurfaceNormal = [&mesh] (const Element2d& el) + { + auto v0 = mesh[el[0]]; + return Cross(mesh[el[1]]-v0, mesh[el[2]]-v0).Normalize(); + }; - map, int> domains_to_surf_index; - map, int> pi_to_edgenr; + // surface index map + Array si_map(mesh.GetNFD()+1); + si_map = -1; - map last_layer_surface_index_map; - int max_surface_index = mesh.GetNFD(); + int fd_old = mesh.GetNFD(); - int max_edge_nr = -1; - for(const auto& seg : mesh.LineSegments()) - if(seg.edgenr > max_edge_nr) - max_edge_nr = seg.edgenr; - - for(int layer = blp.heights.Size(); layer >= 1; layer--) - { - PrintMessage(3, "Generating layer: ", layer); - - auto map_surface_index = [&](auto si) - { - if(last_layer_surface_index_map.find(si) == last_layer_surface_index_map.end()) - { - last_layer_surface_index_map[si] = ++max_surface_index; - auto& old_fd = mesh.GetFaceDescriptor(si); - int domout = blp.outside ? old_fd.DomainOut() : blp.new_matnrs[layer-1]; - int domin = blp.outside ? blp.new_matnrs[layer-1] : old_fd.DomainIn(); - // -1 surf nr is so that curving does not do anything - FaceDescriptor fd(-1, - domin, domout, -1); - fd.SetBCProperty(max_surface_index); - mesh.AddFaceDescriptor(fd); - mesh.SetBCName(max_surface_index-1, - "mapped_" + old_fd.GetBCName()); - return max_surface_index; - } - return last_layer_surface_index_map[si]; - }; - - mesh.UpdateTopology(); - auto& meshtopo = mesh.GetTopology(); - - auto layerht = blp.heights[layer-1]; - - PrintMessage(5, "Layer Height = ", layerht); - - // Need to store the old number of points and - // surface elements because there are new points and - // surface elements being added during the process - int np = mesh.GetNP(); - int nse = mesh.GetNSE(); - int ne = mesh.GetNE(); - - // Safety measure to ensure no issues with mesh - // consistency - int nseg = mesh.GetNSeg(); - - // Indicate which points need to be remapped - BitArray bndnodes(np+1); // big enough for 1-based array - - // Map of the old points to the new points - Array mapto(np); - - // Growth vectors for the prismatic layer based on - // the effective surface normal at a given point - Array, PointIndex> growthvectors(np); - growthvectors = 0.; - - // Bit array to identify all the points belonging - // to the surface of interest - bndnodes.Clear(); - - // Run through all the surface elements and mark the points - // belonging to those where a boundary layer has to be created. - // In addition, also calculate the effective surface normal - // vectors at each of those points to determine the mesh motion - // direction - PrintMessage(3, "Marking points for remapping..."); - - for(const auto& sel : mesh.SurfaceElements()) - if (blp.surfid.Contains(sel.GetIndex())) + // create new FaceDescriptors + for(auto i : Range(1, fd_old+1)) + { + auto& fd = mesh.GetFaceDescriptor(i); + if(blp.surfid.Contains(i)) + { + if(auto isIn = domains.Test(fd.DomainIn()); isIn != domains.Test(fd.DomainOut())) { - auto n2 = GetSurfaceNormal(mesh,sel); - auto& fd = mesh.GetFaceDescriptor(sel.GetIndex()); - auto domin = fd.DomainIn(); - auto domout = fd.DomainOut(); - if(blp.domains.Test(domout) && !blp.domains.Test(domin)) - n2 *= -1; - if(!blp.outside) - n2 *= -1; - for(auto pi : sel.PNums()) - { - // Set the bitarray to indicate that the - // point is part of the required set - bndnodes.SetBit(pi); - - // Add the surface normal to the already existent one - // (This gives the effective normal direction at corners - // and curved areas) - - auto& n1 = growthvectors[pi]; - if(n1.Length() == 0) { n1 = n2; continue; } - auto n1n2 = n1 * n2; - auto n1n1 = n1 * n1; - auto n2n2 = n2 * n2; - if(n2n2 - n1n2*n1n2/n1n1 == 0) { n1 = n2; continue; } - n1 += (n2n2 - n1n2)/(n2n2 - n1n2*n1n2/n1n1) * (n2 - n1n2/n1n1 * n1); - } + int new_si = mesh.GetNFD()+1; + surfacefacs[i] = isIn ? 1. : -1.; + // -1 surf nr is so that curving does not do anything + FaceDescriptor new_fd(-1, isIn ? new_mat_nr : fd.DomainIn(), + isIn ? fd.DomainOut() : new_mat_nr, -1); + new_fd.SetBCProperty(new_si); + mesh.AddFaceDescriptor(new_fd); + si_map[i] = new_si; + mesh.SetBCName(new_si-1, "mapped_" + fd.GetBCName()); } + } + } - // project growthvector on surface for inner angles - for(const auto& sel : mesh.SurfaceElements()) - // if(!blp.surfid.Contains(sel.GetIndex())) - // { - if(blp.project_boundaries.Contains(sel.GetIndex())) + // mark points for remapping + for(const auto& sel : mesh.SurfaceElements()) + { + auto n = surfacefacs[sel.GetIndex()] * getSurfaceNormal(sel); + if(n.Length2() != 0.) + { + for(auto pi : sel.PNums()) { - auto n = GetSurfaceNormal(mesh, sel); - for(auto i : Range(sel.PNums())) - { - auto pi = sel.PNums()[i]; - if(growthvectors[pi].Length2() == 0.) - continue; - auto next = sel.PNums()[(i+1)%sel.GetNV()]; - auto prev = sel.PNums()[i == 0 ? sel.GetNV()-1 : i-1]; - auto v1 = (mesh[next] - mesh[pi]).Normalize(); - auto v2 = (mesh[prev] - mesh[pi]).Normalize(); - auto v3 = growthvectors[pi]; - v3.Normalize(); - // only project if sel goes in boundarylayer direction - if((v1 * v3 < 1e-12) || (v2 * v3 < 1e-12)) - continue; - - auto& g = growthvectors[pi]; - auto ng = n * g; - auto gg = g * g; - auto nn = n * n; - if(fabs(ng*ng-nn*gg) < 1e-12 || fabs(ng) < 1e-12) continue; - auto a = -ng*ng/(ng*ng-nn * gg); - auto b = ng*gg/(ng*ng-nn*gg); - g += a*g + b*n; - } + auto & np = growthvectors[pi]; + if(np.Length() == 0) { np = n; continue; } + auto npn = np * n; + auto npnp = np * np; + auto nn = n * n; + if(nn-npn*npn/npnp == 0) { np = n; continue; } + np += (nn - npn)/(nn - npn*npn/npnp) * (n - npn/npnp * np); } + } + } - if (!blp.grow_edges) - { - for(const auto& sel : mesh.LineSegments()) - { - int count = 0; - for(const auto& sel2 : mesh.LineSegments()) - if(((sel[0] == sel2[0] && sel[1] == sel2[1]) || (sel[0] == sel2[1] && sel[1] == sel2[0])) && blp.surfid.Contains(sel2.si)) - count++; - if(count == 1) - { - bndnodes.Clear(sel[0]); - bndnodes.Clear(sel[1]); - } - } - } + // Bit array to keep track of segments already processed + BitArray segs_done(nseg); + segs_done.Clear(); - // Add additional points into the mesh structure in order to - // clone the surface elements. - // Also invert the growth vectors so that they point inwards, - // and normalize them - PrintMessage(3, "Cloning points and calculating growth vectors..."); + // map for all segments with same points + // points to pair of SegmentIndex, int + // int is type of other segment, either: + // 0 == adjacent surface grows layer + // 1 == adjacent surface doesn't grow layer, but layer ends on it + // 2 == adjacent surface is interior surface that ends on layer + // 3 == adjacent surface is exterior surface that ends on layer (not allowed yet) + Array>, SegmentIndex> segmap(mesh.GetNSeg()); - for (PointIndex pi = 1; pi <= np; pi++) - { - if (bndnodes.Test(pi)) - mapto[pi] = mesh.AddPoint(mesh[pi]); - else - mapto[pi].Invalidate(); - } + // moved segments + Array moved_segs; - // Add quad surface elements at edges for surfaces which - // don't have boundary layers + // boundaries to project endings to + BitArray project_boundaries(fd_old+1); + BitArray move_boundaries(fd_old+1); + project_boundaries.Clear(); + move_boundaries.Clear(); - // Bit array to keep track of segments already processed - BitArray segsel(nseg); + Array seg2surfel(mesh.GetNSeg()); + for(auto si : Range(mesh.SurfaceElements())) + { + NgArray surfeledges; + meshtopo.GetSurfaceElementEdges(si+1, surfeledges); + for(auto edgenr : surfeledges) + for(auto sei : Range(mesh.LineSegments())) + if(meshtopo.GetEdge(sei)+1 == edgenr && + mesh[sei].si == mesh[si].GetIndex()) + seg2surfel[sei] = si; + } - // Set them all to "1" to initially activate all segments - segsel.Set(); - - // remove double segments (if more than 2 surfaces come together - // in one edge. If one of them is mapped, keep that one and - // map the others to it. - Array> segmap(nseg); - for(SegmentIndex sei = 0; sei < nseg; sei++) - { - if(!segsel.Test(sei)) continue; - const auto& segi = mesh[sei]; - for(SegmentIndex sej = 0; sej < nseg; sej++) - { - if(sej == sei || !segsel.Test(sej)) continue; - const auto& segj = mesh[sej]; - if(segi[0] == segj[0] && segi[1] == segj[1]) - { - SegmentIndex main, other; - if(blp.surfid.Contains(segi.si)) - { main = sei; other = sej; } - else { main = sej; other = sei; } - segsel.Clear(other); - for(auto& s : segmap[other]) - segmap[main].Append(s); - segmap[other].SetSize(0); - segmap[main].Append(other); - if(other == sei) sej = nseg; - } - } - } - - PrintMessage(3, "Adding 2D Quad elements on required surfaces..."); - - if(blp.grow_edges) - for(SegmentIndex sei = 0; sei < nseg; sei++) + for(auto si : Range(mesh.LineSegments())) + { + if(segs_done[si]) continue; + const auto& segi = mesh[si]; + if(si_map[segi.si] == -1) continue; + segs_done.SetBit(si); + segmap[si].Append(make_pair(si, 0)); + moved_segs.Append(si); + for(auto sj : Range(mesh.LineSegments())) + { + if(segs_done.Test(sj)) continue; + const auto& segj = mesh[sj]; + if((segi[0] == segj[0] && segi[1] == segj[1]) || + (segi[0] == segj[1] && segi[1] == segj[0])) { - // Only go in if the segment is still active, and if both its - // surface index is part of the "hit-list" - if(segsel.Test(sei)) + segs_done.SetBit(sj); + int type; + if(si_map[segj.si] != -1) + type = 0; + else if(const auto& fd = mesh.GetFaceDescriptor(segj.si); domains.Test(fd.DomainIn()) && domains.Test(fd.DomainOut())) { - // copy here since we will add segments and this would - // invalidate a reference! - auto segi = mesh[sei]; - if(blp.surfid.Contains(segi.si)) - { - // clear the bit to indicate that this segment has been processed - segsel.Clear(sei); - - // Find matching segment pair on other surface - for(SegmentIndex sej = 0; sej < nseg; sej++) - { - // copy here since we will add segments and this would - // invalidate a reference! - auto segj = mesh[sej]; - // Find the segment pair on the neighbouring surface element - // Identified by: seg1[0] = seg_pair[1] and seg1[1] = seg_pair[0] - if(segsel.Test(sej) && ((segi[0] == segj[1]) && (segi[1] == segj[0]))) - { - // clear bit to indicate that processing of this segment is done - segsel.Clear(sej); - - // if segj is not in surfel list we nned to add quads - if(!blp.surfid.Contains(segj.si)) - { - SurfaceElementIndex pnt_commelem; - SetInvalid(pnt_commelem); - - auto pnt1_elems = meshtopo.GetVertexSurfaceElements(segj[0]); - auto pnt2_elems = meshtopo.GetVertexSurfaceElements(segj[1]); - - for(auto pnt1_sei : pnt1_elems) - if(mesh[pnt1_sei].GetIndex() == segj.si) - for(auto pnt2_sei : pnt2_elems) - if(pnt1_sei == pnt2_sei) - pnt_commelem = pnt1_sei; - - if(IsInvalid(pnt_commelem)) - throw Exception("Couldn't find element on other side for " + ToString(segj[0]) + " to " + ToString(segj[1])); - - const auto& commsel = mesh[pnt_commelem]; - Element2d sel(QUAD); - auto seg_p1 = segi[0]; - auto seg_p2 = segi[1]; - if(blp.outside) - Swap(seg_p1, seg_p2); - sel[0] = seg_p1; - sel[1] = seg_p2; - sel[2] = mapto[seg_p2]; - sel[3] = mapto[seg_p1]; - auto domains = make_tuple(commsel.GetIndex(), blp.new_matnrs[layer-1], mesh.GetFaceDescriptor(commsel.GetIndex()).DomainOut()); - - if(domains_to_surf_index.find(domains) == domains_to_surf_index.end()) - { - domains_to_surf_index[domains] = ++max_surface_index; - domains_to_surf_index[make_tuple(max_surface_index, get<1>(domains), get<2>(domains))] = max_surface_index; - FaceDescriptor fd(-1, - get<1>(domains), - get<2>(domains), - -1); - fd.SetBCProperty(max_surface_index); - mesh.AddFaceDescriptor(fd); - mesh.SetBCName(max_surface_index-1, - mesh.GetBCName(get<0>(domains)-1)); - } - auto new_index = domains_to_surf_index[domains]; - sel.SetIndex(new_index); - mesh.AddSurfaceElement(sel); - - // Add segments - Segment seg_1, seg_2; - seg_1[0] = mapto[seg_p1]; - seg_1[1] = seg_p1; - seg_2[0] = seg_p2; - seg_2[1] = mapto[seg_p2]; - auto points = make_tuple(seg_p1, mapto[seg_p1]); - if(pi_to_edgenr.find(points) == pi_to_edgenr.end()) - pi_to_edgenr[points] = ++max_edge_nr; - seg_1.edgenr = pi_to_edgenr[points]; - seg_1[2] = PointIndex::INVALID; - seg_1.si = new_index; - mesh.AddSegment(seg_1); - - points = make_tuple(seg_p2, mapto[seg_p2]); - if(pi_to_edgenr.find(points) == pi_to_edgenr.end()) - pi_to_edgenr[points] = ++max_edge_nr; - - seg_2[2] = PointIndex::INVALID; - seg_2.edgenr = pi_to_edgenr[points]; - seg_2.si = new_index; - mesh.AddSegment(seg_2); - } - - // in last layer insert new segments - if(layer == blp.heights.Size()) - { - max_edge_nr++; - if(!blp.surfid.Contains(segj.si)) - { - Segment s3 = segj; - s3.si = map_surface_index(segj.si)-1; - Swap(s3[0], s3[1]); - if(blp.outside) - { - s3[0] = mapto[s3[0]]; - s3[1] = mapto[s3[1]]; - } - else - s3.edgenr = max_edge_nr; - mesh.AddSegment(s3); - } - Segment s1 = segi; - Segment s2 = segj; - s1.edgenr = max_edge_nr; - s2.edgenr = max_edge_nr; - auto side_surf = domains_to_surf_index[make_tuple(s2.si, blp.new_matnrs[layer-1], mesh.GetFaceDescriptor(s2.si).DomainOut())]; - if(blp.surfid.Contains(segj.si)) - s2.si = map_surface_index(segj.si); - else - { - if(blp.outside) - { - s2.si = side_surf; - } - else - mesh[sej].si = side_surf; - } - s1.si = map_surface_index(s1.si); - s1.surfnr1 = s1.surfnr2 = s2.surfnr1 = s2.surfnr2 = -1; - mesh.AddSegment(s1); - mesh.AddSegment(s2); - } - - segmap.SetSize(mesh.LineSegments().Size()); - for(auto sei2 : segmap[sei]) - { - auto& s = mesh[sei2]; - if(blp.outside && layer == blp.heights.Size()) - { - if(blp.surfid.Contains(s.si)) - s.si = map_surface_index(s.si); - s.edgenr = max_edge_nr; - } - else - { - s[0] = mapto[s[0]]; - s[1] = mapto[s[1]]; - } - } - for(auto sej2 : segmap[sej]) - { - auto& s = mesh[sej2]; - if(blp.outside && layer == blp.heights.Size()) - { - if(blp.surfid.Contains(s.si)) - s.si = map_surface_index(s.si); - s.edgenr = max_edge_nr; - } - else - { - s[0] = mapto[s[0]]; - s[1] = mapto[s[1]]; - } - } - - // do not use segi (not even with reference, since - // mesh.AddSegment will resize segment array and - // invalidate reference), this is why we copy it!!! - mesh[sei][0] = mapto[segi[0]]; - mesh[sei][1] = mapto[segi[1]]; - mesh[sej][0] = mapto[segj[0]]; - mesh[sej][1] = mapto[segj[1]]; - } - } + type = 2; + if(fd.DomainIn() == 0 || fd.DomainOut() == 0) + project_boundaries.SetBit(segj.si); + } + else if(const auto& fd = mesh.GetFaceDescriptor(segj.si); !domains.Test(fd.DomainIn()) && !domains.Test(fd.DomainOut())) + { + type = 3; + if(fd.DomainIn() == 0 || fd.DomainOut() == 0) + project_boundaries.SetBit(segj.si); + move_boundaries.SetBit(segj.si); } else { - // check if it doesn't contain the other edge as well - // and if it doesn't contain both mark them as done and - // if necessary map them - for(SegmentIndex sej = 0; sej 1e-12) || (v2 * v3 > 1e-12)) + in_surface_direction.SetBit(sel.GetIndex()); + + auto& g = growthvectors[pi]; + auto ng = n * g; + auto gg = g * g; + auto nn = n * n; + // if(fabs(ng*ng-nn*gg) < 1e-12 || fabs(ng) < 1e-12) continue; + auto a = -ng*ng/(ng*ng-nn * gg); + auto b = ng*gg/(ng*ng-nn*gg); + g += a*g + b*n; + } + } + } + else + { + for(const auto& seg : mesh.LineSegments()) + { + int count = 0; + for(const auto& seg2 : mesh.LineSegments()) + if(((seg[0] == seg2[0] && seg[1] == seg2[1]) || (seg[0] == seg2[1] && seg[1] == seg2[0])) && blp.surfid.Contains(seg2.si)) + count++; + if(count == 1) + { + growthvectors[seg[0]] = {0., 0., 0.}; + growthvectors[seg[1]] = {0., 0., 0.}; + } + } + } + + // insert new points + for (PointIndex pi = 1; pi <= np; pi++) + if (growthvectors[pi].Length2() != 0) + { + Point<3> p = mesh[pi]; + for(auto i : Range(blp.heights)) + { + p += blp.heights[i] * growthvectors[pi]; + mapto[pi].Append(mesh.AddPoint(p)); + } + } + + // add 2d quads on required surfaces + map, int> seg2edge; + if(blp.grow_edges) + { + for(auto sei : moved_segs) + { + // copy here since we will add segments and this would + // invalidate a reference! + auto segi = mesh[sei]; + for(auto [sej, type] : segmap[sei]) + { + auto segj = mesh[sej]; + if(type == 0) + { + Segment s; + s[0] = mapto[segj[0]].Last(); + s[1] = mapto[segj[1]].Last(); + s[2] = PointIndex::INVALID; + auto pair = s[0] < s[1] ? make_pair(s[0], s[1]) : make_pair(s[1], s[0]); + if(seg2edge.find(pair) == seg2edge.end()) + seg2edge[pair] = ++max_edge_nr; + s.edgenr = seg2edge[pair]; + s.si = si_map[segj.si]; + mesh.AddSegment(s); + } + // here we need to grow the quad elements + else if(type == 1) + { + PointIndex pp1 = segj[1]; + PointIndex pp2 = segj[0]; + if(in_surface_direction.Test(segj.si)) + { + Swap(pp1, pp2); + move_boundaries.SetBit(segj.si); + } + PointIndex p1 = pp1; + PointIndex p2 = pp2; + PointIndex p3, p4; + Segment s0; + s0[0] = p1; + s0[1] = p2; + s0[2] = PointIndex::INVALID; + s0.edgenr = segj.edgenr; + s0.si = segj.si; + mesh.AddSegment(s0); + + for(auto i : Range(blp.heights)) + { + Element2d sel(QUAD); + p3 = mapto[pp2][i]; + p4 = mapto[pp1][i]; + sel[0] = p1; + sel[1] = p2; + sel[2] = p3; + sel[3] = p4; + sel.SetIndex(segj.si); + mesh.AddSurfaceElement(sel); + + // TODO: Too many, would be enough to only add outermost ones + Segment s1; + s1[0] = p2; + s1[1] = p3; + s1[2] = PointIndex::INVALID; + auto pair = make_pair(p2, p3); + if(seg2edge.find(pair) == seg2edge.end()) + seg2edge[pair] = ++max_edge_nr; + s1.edgenr = seg2edge[pair]; + s1.si = segj.si; + mesh.AddSegment(s1); + Segment s2; + s2[0] = p4; + s2[1] = p1; + s2[2] = PointIndex::INVALID; + pair = make_pair(p1, p4); + if(seg2edge.find(pair) == seg2edge.end()) + seg2edge[pair] = ++max_edge_nr; + s2.edgenr = seg2edge[pair]; + s2.si = segj.si; + mesh.AddSegment(s2); + p1 = p4; + p2 = p3; + } + Segment s3; + s3[0] = p3; + s3[1] = p4; + s3[2] = PointIndex::INVALID; + auto pair = p3 < p4 ? make_pair(p3, p4) : make_pair(p4, p3); + if(seg2edge.find(pair) == seg2edge.end()) + seg2edge[pair] = ++max_edge_nr; + s3.edgenr = seg2edge[pair]; + s3.si = segj.si; + mesh.AddSegment(s3); } } + } + } - // add surface elements between layer and old domain - if(layer == blp.heights.Size()) - { - for(SurfaceElementIndex si = 0; si < nse; si++) - { - const auto& sel = mesh[si]; - if(blp.surfid.Contains(sel.GetIndex())) - { - Element2d newel = sel; - newel.SetIndex(map_surface_index(sel.GetIndex())); - mesh.AddSurfaceElement(newel); - } - } - } + for(SurfaceElementIndex si = 0; si < nse; si++) + { + auto& sel = mesh[si]; + if(si_map[sel.GetIndex()] != -1) + { + Array points(sel.PNums()); + if(surfacefacs[sel.GetIndex()] > 0) Swap(points[0], points[2]); + for(auto j : Range(blp.heights)) + { + auto eltype = points.Size() == 3 ? PRISM : HEX; + Element el(eltype); + for(auto i : Range(points)) + el[i] = points[i]; + for(auto i : Range(points)) + points[i] = mapto[sel.PNums()[i]][j]; + if(surfacefacs[sel.GetIndex()] > 0) Swap(points[0], points[2]); + for(auto i : Range(points)) + el[sel.PNums().Size() + i] = points[i]; + el.SetIndex(new_mat_nr); + mesh.AddVolumeElement(el); + } + Element2d newel = sel; + for(auto& p : newel.PNums()) + p = mapto[p].Last(); + newel.SetIndex(si_map[sel.GetIndex()]); + mesh.AddSurfaceElement(newel); + } + if(move_boundaries.Test(sel.GetIndex())) + for(auto& p : sel.PNums()) + if(mapto[p].Size()) + p = mapto[p].Last(); + } - // Add prismatic cells at the boundaries - PrintMessage(3, "Generating prism boundary layer volume elements..."); + for(SegmentIndex sei = 0; sei < nseg; sei++) + { + auto& seg = mesh[sei]; + if(move_boundaries.Test(seg.si)) + for(auto& p : seg.PNums()) + if(mapto[p].Size()) + p = mapto[p].Last(); + } - for (SurfaceElementIndex si = 0; si < nse; si++) - { - const auto& sel = mesh[si]; - if(blp.surfid.Contains(sel.GetIndex())) - { - int classify = 0; - for(auto j : Range(sel.PNums())) - if (mapto[sel[j]].IsValid()) - classify += (1 << j); + for(ElementIndex ei = 0; ei < ne; ei++) + { + auto& el = mesh[ei]; + if(!domains[el.GetIndex()]) + { + for(auto& p : el.PNums()) + if(mapto[p].Size()) + p = mapto[p].Last(); + } + } - if(classify == 0) - continue; - - Element el; - - if(sel.GetType() == TRIG) - { - ELEMENT_TYPE types[] = { PRISM, TET, TET, PYRAMID, - TET, PYRAMID, PYRAMID, PRISM }; - int nums[] = { sel[0], sel[1], sel[2], mapto[sel[0]], mapto[sel[1]], mapto[sel[2]] }; - int vertices[][6] = - { - { 0, 1, 2, 0, 1, 2 }, // should not occur - { 0, 2, 1, 3, 0, 0 }, - { 0, 2, 1, 4, 0, 0 }, - { 0, 1, 4, 3, 2, 0 }, - - { 0, 2, 1, 5, 0, 0 }, - { 2, 0, 3, 5, 1, 0 }, - { 1, 2, 5, 4, 0, 0 }, - { 0, 2, 1, 3, 5, 4 } - }; - if(blp.outside) - { - if(classify != 7) - throw Exception("Outside with non prisms not yet implemented"); - for(auto i : Range(6)) - vertices[7][i] = i; - } - - el = Element(types[classify]); - for(auto i : Range(el.PNums())) - el.PNums()[i] = nums[vertices[classify][i]]; - } - else // sel.GetType() == QUAD - { - int nums[] = { sel[0], sel[1], sel[2], sel[3], - mapto[sel[0]], mapto[sel[1]], - mapto[sel[2]], mapto[sel[3]] }; - ArrayMem vertices; - switch(classify) - { - case 6: - { - if(blp.outside) - throw Exception("Type 6 quad outside layer is not yet implemented!"); - el = Element(PRISM); - vertices = {0, 1, 5, 3, 2, 6}; - break; - } - case 9: - { - if(blp.outside) - throw Exception("Type 9 quad outside layer is not yet implemented!"); - el = Element(PRISM); - vertices = { 1, 4, 0, 2, 7, 3 }; - break; - } - case 15: - { - vertices = { 0, 1, 2, 3, 4, 5, 6, 7 }; - if(!blp.outside) - { - Swap(vertices[1], vertices[3]); - Swap(vertices[5], vertices[7]); - } - el = Element(HEX); - break; - } - default: - throw Exception("Type " + ToString(classify) + " for quad layer not yet implemented!"); - } - for(auto i : Range(el.PNums())) - el.PNums()[i] = nums[vertices[i]]; - } - el.SetIndex(blp.new_matnrs[layer-1]); - mesh.AddVolumeElement(el); - } - } - - // Finally switch the point indices of the surface elements - // to the newly added ones - PrintMessage(3, "Transferring boundary layer surface elements to new vertex references..."); - - for(SurfaceElementIndex sei : Range(nse)) - { - auto& sel = mesh[sei]; - if(!blp.surfid.Contains(sel.GetIndex())) - { - const auto& fd = mesh.GetFaceDescriptor(sel.GetIndex()); - if(blp.outside && - (!blp.domains[fd.DomainIn()] && !blp.domains[fd.DomainOut()])) - continue; - if(!blp.outside && - (blp.domains[fd.DomainIn()] || blp.domains[fd.DomainOut()])) - continue; - } - for(auto& pnum : sel.PNums()) - if(mapto[pnum].IsValid()) - pnum = mapto[pnum]; - } - - for(ElementIndex ei : Range(ne)) - { - auto& el = mesh[ei]; - // only move the elements on the correct side - if(blp.outside ? blp.domains[el.GetIndex()] : !blp.domains[el.GetIndex()]) - for(auto& pnum : el.PNums()) - if(mapto[pnum].IsValid()) - pnum = mapto[pnum]; - } - - // Lock all the prism points so that the rest of the mesh can be - // optimised without invalidating the entire mesh - // for (PointIndex pi = mesh.Points().Begin(); pi < mesh.Points().End(); pi++) - for (PointIndex pi = 1; pi <= np; pi++) - if(bndnodes.Test(pi)) mesh.AddLockedPoint(pi); - - // Now, actually pull back the old surface points to create - // the actual boundary layers - PrintMessage(3, "Moving and optimising boundary layer points..."); - - for (PointIndex i = 1; i <= np; i++) - { - if(bndnodes.Test(i)) - { - MeshPoint pointtomove; - pointtomove = mesh.Point(i); - mesh.Point(i).SetPoint(pointtomove + layerht * growthvectors[i]); - } - } - mesh.Compress(); - } - - for(int i=1; i <= mesh.GetNFD(); i++) + for(auto i : Range(1, fd_old+1)) + if(si_map[i] != -1) { - auto& fd = mesh.GetFaceDescriptor(i); - if(blp.surfid.Contains(fd.BCProperty())) - { - if(blp.outside) - fd.SetDomainOut(blp.new_matnrs[blp.new_matnrs.Size()-1]); - else - fd.SetDomainIn(blp.new_matnrs[blp.new_matnrs.Size()-1]); - } + if(mesh.GetFaceDescriptor(mesh.GetNFD()).DomainIn() == new_mat_nr) + mesh.GetFaceDescriptor(i).SetDomainOut(new_mat_nr); + else + mesh.GetFaceDescriptor(i).SetDomainIn(new_mat_nr); } - - PrintMessage(3, "New NP: ", mesh.GetNP()); - PrintMessage(1, "Boundary Layer Generation....Done!"); - } + } } diff --git a/libsrc/meshing/boundarylayer.hpp b/libsrc/meshing/boundarylayer.hpp index 113d9b1f..1d33fab1 100644 --- a/libsrc/meshing/boundarylayer.hpp +++ b/libsrc/meshing/boundarylayer.hpp @@ -14,7 +14,7 @@ public: // parameters by Philippose .. Array surfid; Array heights; - Array new_matnrs; + string new_mat; BitArray domains; bool outside = false; // set the boundary layer on the outside bool grow_edges = false; diff --git a/libsrc/meshing/python_mesh.cpp b/libsrc/meshing/python_mesh.cpp index caee2d35..083ef684 100644 --- a/libsrc/meshing/python_mesh.cpp +++ b/libsrc/meshing/python_mesh.cpp @@ -1017,9 +1017,8 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m) .def ("BoundaryLayer", [](Mesh & self, variant boundary, variant thickness, - variant material, + string material, variant domain, bool outside, - bool grow_edges, optional project_boundaries) { BoundaryLayerParameters blp; @@ -1050,6 +1049,7 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m) } } } + blp.new_mat = material; if(project_boundaries.has_value()) { @@ -1070,34 +1070,13 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m) blp.heights.Append(val.cast()); } - auto prismlayers = blp.heights.Size(); - auto first_new_mat = self.GetNDomains() + 1; - auto max_dom_nr = first_new_mat; - if(string* pmaterial = get_if(&material); pmaterial) - { - self.SetMaterial(first_new_mat, *pmaterial); - for(auto i : Range(prismlayers)) - blp.new_matnrs.Append(first_new_mat); - } - else - { - auto materials = *get_if(&material); - if(py::len(materials) != prismlayers) - throw Exception("Length of thicknesses and materials must be same!"); - for(auto i : Range(prismlayers)) - { - self.SetMaterial(first_new_mat+i, materials[i].cast()); - blp.new_matnrs.Append(first_new_mat + i); - } - max_dom_nr += prismlayers-1; - } - - blp.domains.SetSize(max_dom_nr + 1); // one based + int nr_domains = self.GetNDomains(); + blp.domains.SetSize(nr_domains + 1); // one based blp.domains.Clear(); if(string* pdomain = get_if(&domain); pdomain) { regex pattern(*pdomain); - for(auto i : Range(1, first_new_mat)) + for(auto i : Range(1, nr_domains+1)) if(regex_match(self.GetMaterial(i), pattern)) blp.domains.SetBit(i); } @@ -1106,19 +1085,15 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m) auto idomain = *get_if(&domain); blp.domains.SetBit(idomain); } - // bits for new domains must be set - if(!outside) - for(auto i : Range(first_new_mat, max_dom_nr+1)) - blp.domains.SetBit(i); blp.outside = outside; - blp.grow_edges = grow_edges; + blp.grow_edges = true; GenerateBoundaryLayer (self, blp); self.UpdateTopology(); }, py::arg("boundary"), py::arg("thickness"), py::arg("material"), py::arg("domains") = ".*", py::arg("outside") = false, - py::arg("grow_edges") = false, py::arg("project_boundaries")=nullopt, + py::arg("project_boundaries")=nullopt, R"delimiter( Add boundary layer to mesh. diff --git a/tests/pytest/test_boundarylayer.py b/tests/pytest/test_boundarylayer.py index 27124613..04c0ee8c 100644 --- a/tests/pytest/test_boundarylayer.py +++ b/tests/pytest/test_boundarylayer.py @@ -18,7 +18,7 @@ def test_boundarylayer(outside, capfd): mesh = unit_cube.GenerateMesh(maxh=0.3) ne_before = mesh.ne layer_surfacenames = ["right", "top", "left", "back", "bottom"] - mesh.BoundaryLayer("|".join(layer_surfacenames), [0.01, 0.02], "layer", outside=outside, grow_edges=True) + mesh.BoundaryLayer("|".join(layer_surfacenames), [0.01, 0.01], "layer", outside=outside) should_ne = ne_before + 2 * GetNSurfaceElements(mesh, layer_surfacenames) assert mesh.ne == should_ne @@ -26,7 +26,7 @@ def test_boundarylayer(outside, capfd): assert not "elements are not matching" in capture.out for side in ["front"]: - mesh.BoundaryLayer(side, [0.001, 0.002], "layer", outside=outside, grow_edges=True) + mesh.BoundaryLayer(side, [0.001, 0.001], "layer", outside=outside) should_ne += 2 * GetNSurfaceElements(mesh, [side]) assert mesh.ne == should_ne capture = capfd.readouterr() @@ -53,8 +53,8 @@ def test_boundarylayer2(outside, version, capfd): geo.CloseSurfaces(top, bot, []) mesh = geo.GenerateMesh() should_ne = mesh.ne + 2 * GetNSurfaceElements(mesh, ["default"], "part") - layersize = 0.05 - mesh.BoundaryLayer("default", [0.5 * layersize, layersize], "part", domains="part", outside=outside, grow_edges=True) + layersize = 0.025 + mesh.BoundaryLayer("default", [layersize, layersize], "part", domains="part", outside=outside) assert mesh.ne == should_ne assert not "elements are not matching" in capfd.readouterr().out import netgen.gui @@ -73,8 +73,7 @@ def test_wrong_orientation(outside): mesh = geo.GenerateMesh() - mesh.BoundaryLayer(".*", 0.1, "air", domains="air", outside=outside, - grow_edges=True) + mesh.BoundaryLayer(".*", 0.1, "air", domains="air", outside=outside) ngs = pytest.importorskip("ngsolve") mesh = ngs.Mesh(mesh) assert ngs.Integrate(1, mesh) == pytest.approx(1.2**3 if outside else 1) @@ -88,8 +87,7 @@ def test_splitted_surface(): geo.Add((brick*slots).mat("slot")) mesh = geo.GenerateMesh() - mesh.BoundaryLayer(".*", [0.001, 0.002], "block", "block", outside=False, - grow_edges=True) + mesh.BoundaryLayer(".*", [0.001, 0.001], "block", "block", outside=False) ngs = pytest.importorskip("ngsolve") mesh = ngs.Mesh(mesh) assert ngs.Integrate(1, mesh) == pytest.approx(1) From 1a93fb3fa5da003be01ed72c547dd97337b97f54 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Wed, 18 Nov 2020 20:20:35 +0100 Subject: [PATCH 252/384] first attempt on memory tracing --- libsrc/core/array.hpp | 18 ++++++ libsrc/core/paje_trace.cpp | 29 +++++++++- libsrc/core/paje_trace.hpp | 38 ++++++++++++ libsrc/core/profiler.cpp | 2 + libsrc/core/profiler.hpp | 87 ++++++++++++++++++++++++++++ libsrc/core/python_ngcore_export.cpp | 4 +- libsrc/meshing/meshclass.hpp | 9 +++ 7 files changed, 183 insertions(+), 4 deletions(-) diff --git a/libsrc/core/array.hpp b/libsrc/core/array.hpp index 864fd454..350eb58e 100644 --- a/libsrc/core/array.hpp +++ b/libsrc/core/array.hpp @@ -11,6 +11,7 @@ #include "archive.hpp" #include "exception.hpp" #include "localheap.hpp" +#include "profiler.hpp" #include "utils.hpp" namespace ngcore @@ -654,6 +655,8 @@ namespace ngcore /// that's the data we have to delete, nullptr for not owning the memory T * mem_to_delete; + int mem_tracing_id = 0; + using FlatArray::size; using FlatArray::data; using FlatArray::BASE; @@ -1038,6 +1041,18 @@ namespace ngcore ngcore::Swap (data, b.data); ngcore::Swap (allocsize, b.allocsize); ngcore::Swap (mem_to_delete, b.mem_to_delete); + ngcore::Swap (mem_tracing_id, b.mem_tracing_id); + } + + NETGEN_INLINE void SetMemoryTracing (int mem_id) + { + if(!mem_tracing_id && mem_id) + TraceMemoryAlloc(mem_id, sizeof(T)*allocsize); + + if(mem_tracing_id && !mem_id) + TraceMemoryFree(mem_tracing_id, sizeof(T)*allocsize); + + mem_tracing_id = mem_id; } private: @@ -1053,6 +1068,8 @@ namespace ngcore { size_t nsize = 2 * allocsize; if (nsize < minsize) nsize = minsize; + + TraceMemoryAlloc(mem_tracing_id, sizeof(T)*nsize ); T * hdata = data; data = new T[nsize]; @@ -1069,6 +1086,7 @@ namespace ngcore for (size_t i = 0; i < mins; i++) data[i] = std::move(hdata[i]); #endif delete [] mem_to_delete; + TraceMemoryFree( mem_tracing_id, sizeof(T)*allocsize ); } mem_to_delete = data; diff --git a/libsrc/core/paje_trace.cpp b/libsrc/core/paje_trace.cpp index c58912a4..1c4843a6 100644 --- a/libsrc/core/paje_trace.cpp +++ b/libsrc/core/paje_trace.cpp @@ -36,6 +36,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 +63,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 +74,7 @@ namespace ngcore start_time = GetTimeCounter(); tracing_enabled = true; + mem_tracing_enabled = true; } PajeTrace :: ~PajeTrace() @@ -94,6 +97,9 @@ namespace ngcore for(auto & link : llink) link.time -= start_time; + for(auto & m : memory_events) + m.time -= start_time; + NgMPI_Comm comm(MPI_COMM_WORLD); if(comm.Size()==1) @@ -426,6 +432,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 +440,20 @@ 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; + if(mem_tracing_enabled) + { + variable_type_memory = paje.DefineVariableType( container_type_task_manager, "Memory [MB]" ); + paje.SetVariable( 0, variable_type_memory, container_type_memory, 0.0 ); + } + + const int container_memory = paje.CreateContainer( container_type_memory, container_task_manager, "Memory" ); + int num_nodes = 1; //task_manager ? task_manager->GetNumNodes() : 1; std::vector thread_aliases; @@ -509,6 +524,14 @@ namespace ngcore paje.PopState( j.stop_time, state_type_job, container_jobs ); } + for(const auto & m : memory_events) + { + if(m.is_alloc) + paje.AddVariable( m.time, variable_type_memory, container_memory, 1.0*m.size / (1024*1024)); + else + paje.SubVariable( m.time, variable_type_memory, container_memory, 1.0*m.size / (1024*1024)); + } + std::set timer_ids; std::map timer_aliases; std::map timer_names; diff --git a/libsrc/core/paje_trace.hpp b/libsrc/core/paje_trace.hpp index 95c42d4a..84227fb4 100644 --- a/libsrc/core/paje_trace.hpp +++ b/libsrc/core/paje_trace.hpp @@ -23,6 +23,7 @@ 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; @@ -35,6 +36,11 @@ namespace ngcore // 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 +102,21 @@ namespace ngcore bool operator < (const ThreadLink & other) const { return time < other.time; } }; + struct MemoryEvent + { + TTimePoint time; + size_t size; + int region_id; + bool is_alloc; + + bool operator < (const MemoryEvent & other) const { return time < other.time; } + }; + std::vector > tasks; std::vector jobs; std::vector timer_events; std::vector > links; + std::vector memory_events; public: NGCORE_API void StopTracing(); @@ -129,6 +146,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; diff --git a/libsrc/core/profiler.cpp b/libsrc/core/profiler.cpp index 1190e6fe..73aad63d 100644 --- a/libsrc/core/profiler.cpp +++ b/libsrc/core/profiler.cpp @@ -113,5 +113,7 @@ namespace ngcore NgProfiler prof; // NOLINT + std::vector MemoryTracer::names{"root"}; + std::map< int, std::vector > MemoryTracer::tree; } // namespace ngcore diff --git a/libsrc/core/profiler.hpp b/libsrc/core/profiler.hpp index c16c242c..12233db1 100644 --- a/libsrc/core/profiler.hpp +++ b/libsrc/core/profiler.hpp @@ -3,6 +3,7 @@ #include #include +#include #include #include "logging.hpp" @@ -299,6 +300,92 @@ namespace ngcore return tres; } + + class MemoryTracer + { + NGCORE_API static std::vector names; + static int GetId(std::string name) + { + int id = names.size(); + names.push_back(name); + if(id==10*NgProfiler::SIZE) + std::cerr << "Allocated " << id << " MemoryTracer objects" << std::endl; + return id; + } + + NGCORE_API static std::map< int, std::vector > tree; + + int id; + std::vector> tracks; + + public: + + MemoryTracer( std::string name ) + { + id = GetId(name); + } + + template + MemoryTracer( std::string name, TRest & ... rest ) + { + id = GetId(name); + Track(rest...); + } + + template + void Track( T1 & obj, std::string name, TRest & ... rest ) + { + Track(obj, name); + Track(rest...); + } + + template + void Track( T & obj, std::string name ) + { + int child_id = GetId(name); + tree[id].push_back(child_id); + obj.SetMemoryTracing(child_id); + tracks.push_back( [&obj] () { obj.SetMemoryTracing(0); } ); + } + + template + void Track( T & obj ) + { + auto & mt = obj.GetMemoryTracer(); + int child_id = mt.id; + tree[id].push_back(child_id); + } + + void StopTracking() + { + for(auto & f : tracks) + f(); + tracks.clear(); + } + + static std::string GetName(int id) + { + return names[id]; + } + + ~MemoryTracer() + { + StopTracking(); + } + }; + + NETGEN_INLINE void TraceMemoryAlloc( int mem_id, size_t size ) + { + if(mem_id && trace) + trace->AllocMemory(mem_id, size); + } + + NETGEN_INLINE void TraceMemoryFree( int mem_id, size_t size ) + { + if(mem_id && trace) + trace->FreeMemory(mem_id, size); + } + } // namespace ngcore // Helper macro to easily add multiple timers in a function for profiling diff --git a/libsrc/core/python_ngcore_export.cpp b/libsrc/core/python_ngcore_export.cpp index 4f93168e..08d41ef4 100644 --- a/libsrc/core/python_ngcore_export.cpp +++ b/libsrc/core/python_ngcore_export.cpp @@ -247,15 +247,17 @@ threads : int ; py::class_(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) { }) diff --git a/libsrc/meshing/meshclass.hpp b/libsrc/meshing/meshclass.hpp index 1de31c97..aab4e87a 100644 --- a/libsrc/meshing/meshclass.hpp +++ b/libsrc/meshing/meshclass.hpp @@ -925,6 +925,15 @@ namespace netgen shared_ptr 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) From f143995f27e140155d851636d176d9107cde3288 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Wed, 18 Nov 2020 21:45:00 +0100 Subject: [PATCH 253/384] clean up memory tracing --- libsrc/core/paje_trace.cpp | 10 +++++----- libsrc/core/profiler.hpp | 14 -------------- 2 files changed, 5 insertions(+), 19 deletions(-) diff --git a/libsrc/core/paje_trace.cpp b/libsrc/core/paje_trace.cpp index 1c4843a6..23dcb154 100644 --- a/libsrc/core/paje_trace.cpp +++ b/libsrc/core/paje_trace.cpp @@ -446,14 +446,13 @@ namespace ngcore const int container_jobs = paje.CreateContainer( container_type_jobs, container_task_manager, "Jobs" ); 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]" ); - paje.SetVariable( 0, variable_type_memory, container_type_memory, 0.0 ); + paje.SetVariable( 0, variable_type_memory, container_memory, 0.0 ); } - const int container_memory = paje.CreateContainer( container_type_memory, container_task_manager, "Memory" ); - int num_nodes = 1; //task_manager ? task_manager->GetNumNodes() : 1; std::vector thread_aliases; @@ -526,10 +525,11 @@ namespace ngcore for(const auto & m : memory_events) { + double size = 1.0*m.size/(1024*1024); if(m.is_alloc) - paje.AddVariable( m.time, variable_type_memory, container_memory, 1.0*m.size / (1024*1024)); + paje.AddVariable( m.time, variable_type_memory, container_memory, size); else - paje.SubVariable( m.time, variable_type_memory, container_memory, 1.0*m.size / (1024*1024)); + paje.SubVariable( m.time, variable_type_memory, container_memory, size); } std::set timer_ids; diff --git a/libsrc/core/profiler.hpp b/libsrc/core/profiler.hpp index 12233db1..d3b06746 100644 --- a/libsrc/core/profiler.hpp +++ b/libsrc/core/profiler.hpp @@ -316,7 +316,6 @@ namespace ngcore NGCORE_API static std::map< int, std::vector > tree; int id; - std::vector> tracks; public: @@ -345,7 +344,6 @@ namespace ngcore int child_id = GetId(name); tree[id].push_back(child_id); obj.SetMemoryTracing(child_id); - tracks.push_back( [&obj] () { obj.SetMemoryTracing(0); } ); } template @@ -356,22 +354,10 @@ namespace ngcore tree[id].push_back(child_id); } - void StopTracking() - { - for(auto & f : tracks) - f(); - tracks.clear(); - } - static std::string GetName(int id) { return names[id]; } - - ~MemoryTracer() - { - StopTracking(); - } }; NETGEN_INLINE void TraceMemoryAlloc( int mem_id, size_t size ) From a17066a387b28b7ae277a3a82ed8adac5f425c93 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Thu, 19 Nov 2020 14:57:45 +0100 Subject: [PATCH 254/384] html chart for peak memory consumption, some Array tracing fixes --- libsrc/core/array.hpp | 12 +- libsrc/core/paje_trace.cpp | 277 ++++++++++++++++++++++++++---------- libsrc/core/paje_trace.hpp | 2 +- libsrc/core/profiler.hpp | 89 ++++++++++-- libsrc/core/taskmanager.cpp | 2 +- 5 files changed, 290 insertions(+), 92 deletions(-) diff --git a/libsrc/core/array.hpp b/libsrc/core/array.hpp index 350eb58e..db5d7561 100644 --- a/libsrc/core/array.hpp +++ b/libsrc/core/array.hpp @@ -701,6 +701,8 @@ namespace ngcore NETGEN_INLINE Array (Array && a2) { + TraceMemoryChange(mem_tracing_id, sizeof(T)*(a2.allocsize-allocsize)); + size = a2.size; data = a2.data; allocsize = a2.allocsize; @@ -772,6 +774,7 @@ namespace ngcore NETGEN_INLINE ~Array() { delete [] mem_to_delete; + TraceMemoryFree(mem_tracing_id, sizeof(T)*allocsize); } // Only provide this function if T is archivable @@ -826,6 +829,7 @@ namespace ngcore NETGEN_INLINE const Array & Assign (size_t asize, LocalHeap & lh) { delete [] mem_to_delete; + TraceMemoryFree(mem_tracing_id, sizeof(T)*allocsize); size = allocsize = asize; data = lh.Alloc (asize); mem_to_delete = nullptr; @@ -933,6 +937,7 @@ namespace ngcore NETGEN_INLINE void DeleteAll () { delete [] mem_to_delete; + TraceMemoryFree(mem_tracing_id, sizeof(T)*allocsize); mem_to_delete = NULL; data = 0; size = allocsize = 0; @@ -964,6 +969,8 @@ namespace ngcore /// steal array NETGEN_INLINE Array & operator= (Array && a2) { + TraceMemoryChange(mem_tracing_id, sizeof(T)*(a2.allocsize-allocsize)); + ngcore::Swap (size, a2.size); ngcore::Swap (data, a2.data); ngcore::Swap (allocsize, a2.allocsize); @@ -1037,6 +1044,8 @@ namespace ngcore NETGEN_INLINE void Swap (Array & b) { + TraceMemoryChange(mem_tracing_id, sizeof(T)*(b.allocsize-allocsize)); + ngcore::Swap (size, b.size); ngcore::Swap (data, b.data); ngcore::Swap (allocsize, b.allocsize); @@ -1068,11 +1077,10 @@ namespace ngcore { size_t nsize = 2 * allocsize; if (nsize < minsize) nsize = minsize; - - TraceMemoryAlloc(mem_tracing_id, sizeof(T)*nsize ); T * hdata = data; data = new T[nsize]; + TraceMemoryAlloc(mem_tracing_id, sizeof(T)*nsize ); if (hdata) { diff --git a/libsrc/core/paje_trace.cpp b/libsrc/core/paje_trace.cpp index 23dcb154..fdf8a28b 100644 --- a/libsrc/core/paje_trace.cpp +++ b/libsrc/core/paje_trace.cpp @@ -243,7 +243,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; } @@ -809,24 +810,25 @@ namespace ngcore int id = 0; std::map 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) { @@ -834,7 +836,7 @@ namespace ngcore f << ", children: ["; for(auto & c : n.children) { - PrintNode(c.second, level, f); + PrintNode(c.second, f); if(++i + + + + +)CODE_"; + if(!time_or_memory) + f << "Maximum Memory Consumption\n"; + f << R"CODE_( + + +
+ + + +)CODE_" << std::endl; + + + } + + void WriteMemorySunburstHTML( std::vector & events, std::string filename ) + { + size_t mem_allocated; + size_t max_mem_allocated; + size_t imax_mem_allocated; + + const auto & names = MemoryTracer::GetNames(); + const auto & tree = MemoryTracer::GetTree(); + auto N = names.size(); + + Array mem_allocated_id(N); + mem_allocated_id = 0; + + // Find point with maximum memory allocation, check for missing allocs/frees + for(auto i : IntRange(events.size())) + { + const auto & ev = events[i]; + + if(ev.is_alloc) + { + mem_allocated += ev.size; + mem_allocated_id[ev.id] += ev.size; + if(mem_allocated > max_mem_allocated) + { + 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; + 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 -= ev.size; + 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 = events[i]; + + if(ev.is_alloc) + mem_allocated_id[ev.id] += ev.size; + else + mem_allocated_id[ev.id] -= ev.size; + } + + TreeNode root; + root.name="all"; + + Array nodes(N); + nodes = nullptr; + + // find root nodes in memory tracer tree, i.e. they have no parents + Array parents(N); + parents = -1; + for( const auto & [iparent, children] : tree ) + for (auto child_id : children) + { + if(parents[child_id] != -1) + std::cerr << "Error in memory tracer: multiple parents found for " << names[child_id] << std::endl; + parents[child_id] = iparent; + } + + for(auto i : IntRange(1, N)) + { + TreeNode * parent = &root; + if(parents[i]!=-1) + 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 : IntRange(1, N)) + if(parents[N-i]==-1) + root.size += nodes[N-i]->size; + else + nodes[parents[N-i]]->size += nodes[N-i]->size; + + WriteSunburstHTML( root, filename, false ); + + } + void PajeTrace::WriteSunburstHTML( ) { std::vector events; @@ -884,10 +1063,10 @@ namespace ngcore std::sort (events.begin(), events.end()); - root.time = 1000.0*static_cast(stop_time) * seconds_per_tick; + root.size = 1000.0*static_cast(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) { @@ -904,7 +1083,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; } @@ -916,73 +1095,23 @@ namespace ngcore std::cout << "node stack empty!" << std::endl; break; } - double time = 1000.0*static_cast(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(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_( - - - - - - - -
- - - -)CODE_" << std::endl; + ngcore::WriteSunburstHTML( root, tracefile_name, true ); + WriteMemorySunburstHTML( memory_events, tracefile_name+"_memory" ); } } // namespace ngcore diff --git a/libsrc/core/paje_trace.hpp b/libsrc/core/paje_trace.hpp index 84227fb4..22fd0f50 100644 --- a/libsrc/core/paje_trace.hpp +++ b/libsrc/core/paje_trace.hpp @@ -106,7 +106,7 @@ namespace ngcore { TTimePoint time; size_t size; - int region_id; + int id; bool is_alloc; bool operator < (const MemoryEvent & other) const { return time < other.time; } diff --git a/libsrc/core/profiler.hpp b/libsrc/core/profiler.hpp index d3b06746..ab9785ea 100644 --- a/libsrc/core/profiler.hpp +++ b/libsrc/core/profiler.hpp @@ -300,10 +300,48 @@ namespace ngcore return tres; } + class MemoryTracer; + + namespace detail + { + //Type trait to check if a class implements a 'const MemoryTracer& GetMemoryTracer()' function + template + struct has_GetMemoryTracer + { + private: + template + static constexpr auto check(T2*) -> + typename std::is_same().GetMemoryTracer()),const MemoryTracer &>::type; + template + static constexpr std::false_type check(...); + using type = decltype(check(nullptr)); // NOLINT + public: + static constexpr bool value = type::value; + }; + + //Type trait to check if a class implements a 'void SetMemoryTacing(int)' function + template + struct has_SetMemoryTracing + { + private: + template + static constexpr auto check(T2*) -> + typename std::is_same().SetMemoryTracing(0)),void>::type; + template + static constexpr std::false_type check(...); + using type = decltype(check(nullptr)); // NOLINT + public: + static constexpr bool value = type::value; + }; + + + } // namespace detail class MemoryTracer { NGCORE_API static std::vector names; + NGCORE_API static std::map< int, std::vector > tree; + static int GetId(std::string name) { int id = names.size(); @@ -313,7 +351,6 @@ namespace ngcore return id; } - NGCORE_API static std::map< int, std::vector > tree; int id; @@ -332,32 +369,50 @@ namespace ngcore } template - void Track( T1 & obj, std::string name, TRest & ... rest ) + void Track( T1 & obj, std::string name, TRest & ... rest ) const { Track(obj, name); Track(rest...); } template - void Track( T & obj, std::string name ) + void Track( T & obj, std::string name ) const { - int child_id = GetId(name); - tree[id].push_back(child_id); - obj.SetMemoryTracing(child_id); - } - - template - void Track( T & obj ) - { - auto & mt = obj.GetMemoryTracer(); - int child_id = mt.id; - tree[id].push_back(child_id); + if constexpr(detail::has_SetMemoryTracing::value) + { + int child_id = GetId(name); + tree[id].push_back(child_id); + obj.SetMemoryTracing(child_id); + } + if constexpr(detail::has_GetMemoryTracer::value) + { + auto & mt = obj.GetMemoryTracer(); + int child_id = mt.id; + if(name!="") + names[mt.id] = name; + tree[id].push_back(child_id); + } } static std::string GetName(int id) { return names[id]; } + + std::string GetName() const + { + return names[id]; + } + + void SetName(std::string name) const + { + names[id] = name; + } + + + static const std::vector & GetNames() { return names; } + static const std::map> & GetTree() { return tree; } + }; NETGEN_INLINE void TraceMemoryAlloc( int mem_id, size_t size ) @@ -372,6 +427,12 @@ namespace ngcore trace->FreeMemory(mem_id, size); } + NETGEN_INLINE void TraceMemoryChange( int mem_id, long long size ) + { + if(mem_id && trace) + trace->ChangeMemory(mem_id, size); + } + } // namespace ngcore // Helper macro to easily add multiple timers in a function for profiling diff --git a/libsrc/core/taskmanager.cpp b/libsrc/core/taskmanager.cpp index be345321..a1049a1c 100644 --- a/libsrc/core/taskmanager.cpp +++ b/libsrc/core/taskmanager.cpp @@ -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++)); } From b00c56a012064e61dc9070cbd7eb63e6caaa5b81 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Thu, 19 Nov 2020 14:58:16 +0100 Subject: [PATCH 255/384] mem tracing - set name for tempmesh in delaunay --- libsrc/meshing/delaunay.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libsrc/meshing/delaunay.cpp b/libsrc/meshing/delaunay.cpp index adc64712..cd675ef3 100644 --- a/libsrc/meshing/delaunay.cpp +++ b/libsrc/meshing/delaunay.cpp @@ -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); From 6f98123e98c098e7a512e283591d20692e7454ca Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Thu, 19 Nov 2020 16:16:39 +0100 Subject: [PATCH 256/384] mem tracing - use topological sorting, some fixes --- libsrc/core/paje_trace.cpp | 57 ++++++++++++++++++++++++++++---------- 1 file changed, 43 insertions(+), 14 deletions(-) diff --git a/libsrc/core/paje_trace.cpp b/libsrc/core/paje_trace.cpp index fdf8a28b..856e2214 100644 --- a/libsrc/core/paje_trace.cpp +++ b/libsrc/core/paje_trace.cpp @@ -931,15 +931,16 @@ namespace ngcore void WriteMemorySunburstHTML( std::vector & events, std::string filename ) { - size_t mem_allocated; - size_t max_mem_allocated; - size_t imax_mem_allocated; + size_t mem_allocated = 0; + size_t max_mem_allocated = 0; + size_t imax_mem_allocated = 0; const auto & names = MemoryTracer::GetNames(); const auto & tree = MemoryTracer::GetTree(); - auto N = names.size(); + size_t N = names.size(); - Array mem_allocated_id(N); + Array mem_allocated_id; + mem_allocated_id.SetSize(N); mem_allocated_id = 0; // Find point with maximum memory allocation, check for missing allocs/frees @@ -984,11 +985,16 @@ namespace ngcore TreeNode root; root.name="all"; - Array nodes(N); + Array nodes; + nodes.SetSize(N); nodes = nullptr; + Array sorting; // topological sorting (parents before children) + sorting.SetAllocSize(N); + ArrayMem stack; // find root nodes in memory tracer tree, i.e. they have no parents - Array parents(N); + Array parents; + parents.SetSize(N); parents = -1; for( const auto & [iparent, children] : tree ) for (auto child_id : children) @@ -999,10 +1005,29 @@ namespace ngcore } for(auto i : IntRange(1, N)) + if(parents[i]==-1) + { + sorting.Append(i); + if(tree.count(i)) + stack.Append(i); + } + + while(stack.Size()) { - TreeNode * parent = &root; - if(parents[i]!=-1) - parent = nodes[parents[i]]; + auto current = stack.Last(); + stack.DeleteLast(); + + for(const auto child : tree.at(current)) + { + sorting.Append(child); + if(tree.count(child)) + stack.Append(child); + } + } + + for(auto i : sorting) + { + TreeNode * parent = (parents[i]==-1) ? &root : nodes[parents[i]]; auto & node = parent->children[i]; nodes[i] = &node; @@ -1012,11 +1037,15 @@ namespace ngcore node.name = names[i]; } - for(auto i : IntRange(1, N)) - if(parents[N-i]==-1) - root.size += nodes[N-i]->size; + for(auto i_ : Range(sorting)) + { + // reverse topological order to accumulate total memory usage of all children + auto i = sorting[sorting.Size()-1-i_]; + if(parents[i]==-1) + root.size += nodes[i]->size; else - nodes[parents[N-i]]->size += nodes[N-i]->size; + nodes[parents[i]]->size += nodes[i]->size; + } WriteSunburstHTML( root, filename, false ); From f0152baacfdf79a1353e1a88fc21540fcfcc7903 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Thu, 19 Nov 2020 17:35:29 +0100 Subject: [PATCH 257/384] mem tracing - TraceMemorySwap helper function --- libsrc/core/array.hpp | 7 +++---- libsrc/core/profiler.hpp | 22 ++++++++++++++++++++++ 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/libsrc/core/array.hpp b/libsrc/core/array.hpp index db5d7561..60132186 100644 --- a/libsrc/core/array.hpp +++ b/libsrc/core/array.hpp @@ -701,7 +701,7 @@ namespace ngcore NETGEN_INLINE Array (Array && a2) { - TraceMemoryChange(mem_tracing_id, sizeof(T)*(a2.allocsize-allocsize)); + TraceMemorySwap(mem_tracing_id, sizeof(T)*allocsize, a2.mem_tracing_id, sizeof(T)*a2.allocsize); size = a2.size; data = a2.data; @@ -969,7 +969,7 @@ namespace ngcore /// steal array NETGEN_INLINE Array & operator= (Array && a2) { - TraceMemoryChange(mem_tracing_id, sizeof(T)*(a2.allocsize-allocsize)); + TraceMemorySwap(mem_tracing_id, sizeof(T)*allocsize, a2.mem_tracing_id, sizeof(T)*a2.allocsize); ngcore::Swap (size, a2.size); ngcore::Swap (data, a2.data); @@ -1044,13 +1044,12 @@ namespace ngcore NETGEN_INLINE void Swap (Array & b) { - TraceMemoryChange(mem_tracing_id, sizeof(T)*(b.allocsize-allocsize)); + TraceMemorySwap(mem_tracing_id, sizeof(T)*allocsize, b.mem_tracing_id, 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); - ngcore::Swap (mem_tracing_id, b.mem_tracing_id); } NETGEN_INLINE void SetMemoryTracing (int mem_id) diff --git a/libsrc/core/profiler.hpp b/libsrc/core/profiler.hpp index ab9785ea..cb07d053 100644 --- a/libsrc/core/profiler.hpp +++ b/libsrc/core/profiler.hpp @@ -433,6 +433,28 @@ namespace ngcore trace->ChangeMemory(mem_id, size); } + NETGEN_INLINE void TraceMemorySwap( int mem_id, size_t size, int mem_id2, size_t size2 ) + { + if(!trace || (mem_id==0 && mem_id2==0)) + return; + if(mem_id == 0) + return trace->ChangeMemory(mem_id2, size-size2); + if(mem_id2 == 0) + return trace->ChangeMemory(mem_id, size2-size); + + // first decrease memory, otherwise have artificial/wrong high peak memory usage + if(sizeChangeMemory(mem_id2, size-size2); + trace->ChangeMemory(mem_id, size2-size); + } + else + { + trace->ChangeMemory(mem_id, size2-size); + trace->ChangeMemory(mem_id2, size-size2); + } + } + } // namespace ngcore // Helper macro to easily add multiple timers in a function for profiling From 87623981a6c66df3d439ba951b64e9dc700361d6 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Thu, 19 Nov 2020 19:29:04 +0100 Subject: [PATCH 258/384] export PajeTrace.WriteMemoryChart() to python --- libsrc/core/paje_trace.cpp | 18 ++++++++++-------- libsrc/core/paje_trace.hpp | 3 ++- libsrc/core/python_ngcore_export.cpp | 7 ++++--- 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/libsrc/core/paje_trace.cpp b/libsrc/core/paje_trace.cpp index 856e2214..4e5331e6 100644 --- a/libsrc/core/paje_trace.cpp +++ b/libsrc/core/paje_trace.cpp @@ -742,7 +742,8 @@ namespace ngcore } } } - WriteSunburstHTML(); + WriteTimingChart(); + WriteMemoryChart(""); paje.WriteEvents(); } @@ -929,8 +930,10 @@ namespace ngcore } - void WriteMemorySunburstHTML( std::vector & events, std::string filename ) + 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; @@ -944,9 +947,9 @@ namespace ngcore mem_allocated_id = 0; // Find point with maximum memory allocation, check for missing allocs/frees - for(auto i : IntRange(events.size())) + for(auto i : IntRange(memory_events.size())) { - const auto & ev = events[i]; + const auto & ev = memory_events[i]; if(ev.is_alloc) { @@ -974,7 +977,7 @@ namespace ngcore mem_allocated_id = 0; for(auto i : IntRange(imax_mem_allocated+1)) { - const auto & ev = events[i]; + const auto & ev = memory_events[i]; if(ev.is_alloc) mem_allocated_id[ev.id] += ev.size; @@ -1047,11 +1050,11 @@ namespace ngcore nodes[parents[i]]->size += nodes[i]->size; } - WriteSunburstHTML( root, filename, false ); + WriteSunburstHTML( root, fname, false ); } - void PajeTrace::WriteSunburstHTML( ) + void PajeTrace::WriteTimingChart( ) { std::vector events; @@ -1140,7 +1143,6 @@ namespace ngcore root.chart_size = 0.0; ngcore::WriteSunburstHTML( root, tracefile_name, true ); - WriteMemorySunburstHTML( memory_events, tracefile_name+"_memory" ); } } // namespace ngcore diff --git a/libsrc/core/paje_trace.hpp b/libsrc/core/paje_trace.hpp index 22fd0f50..421f866e 100644 --- a/libsrc/core/paje_trace.hpp +++ b/libsrc/core/paje_trace.hpp @@ -30,7 +30,8 @@ namespace ngcore int nthreads; public: - void WriteSunburstHTML(); + NGCORE_API void WriteTimingChart(); + NGCORE_API void WriteMemoryChart( std::string fname ); // Approximate number of events to trace. Tracing will // be stopped if any thread reaches this number of events diff --git a/libsrc/core/python_ngcore_export.cpp b/libsrc/core/python_ngcore_export.cpp index 08d41ef4..59d1a13f 100644 --- a/libsrc/core/python_ngcore_export.cpp +++ b/libsrc/core/python_ngcore_export.cpp @@ -263,9 +263,10 @@ threads : int .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) + .def_static("WriteMemoryChart", [](string filename){ if(trace) trace->WriteMemoryChart(filename); }, py::arg("filename")="memory" ) ; From f5771dca1e4b298ca6d7820c51b6aa3235f4b726 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20Sch=C3=B6berl?= Date: Thu, 19 Nov 2020 20:07:03 +0100 Subject: [PATCH 259/384] fix for 2D curves with same sub-domain on both sides --- libsrc/geom2d/genmesh2d.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libsrc/geom2d/genmesh2d.cpp b/libsrc/geom2d/genmesh2d.cpp index 4ddd0370..61753f72 100644 --- a/libsrc/geom2d/genmesh2d.cpp +++ b/libsrc/geom2d/genmesh2d.cpp @@ -482,7 +482,8 @@ namespace netgen for (const Segment & seg : mesh->LineSegments()) { dom2seg_creator.Add (seg.domin, &seg); - dom2seg_creator.Add (seg.domout, &seg); + if (seg.domin != seg.domout) + dom2seg_creator.Add (seg.domout, &seg); } auto dom2seg = dom2seg_creator.MoveTable(); From 6b30ec0b7c3430e89416d5cf2f34269ac09b2953 Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Thu, 19 Nov 2020 21:54:58 +0100 Subject: [PATCH 260/384] test case for leftdom==rightdom in geom2d --- tests/pytest/test_geom2d.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 tests/pytest/test_geom2d.py diff --git a/tests/pytest/test_geom2d.py b/tests/pytest/test_geom2d.py new file mode 100644 index 00000000..d40fd40a --- /dev/null +++ b/tests/pytest/test_geom2d.py @@ -0,0 +1,13 @@ +from netgen.geom2d import SplineGeometry + + +def test_leftdom_equals_rightdom(): + geo = SplineGeometry() + pnts = [(0,0), (1,0), (2,0), (2,1), (1,1), (0,1)] + gp = [geo.AppendPoint(*p) for p in pnts] + lines = [(0,1,0), (1,2,0), (2,3,0), (3,4,0), (4,5,0), (5,0,0), (1,4,1)] + for p1, p2, rd in lines: + geo.Append(["line", p1, p2], leftdomain=1, rightdomain=rd) + + mesh = geo.GenerateMesh() + From 3440a43e99c52717295505a7f493b80c7322cf33 Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Thu, 19 Nov 2020 22:36:30 +0100 Subject: [PATCH 261/384] don't use (maybe invalidated) reference after array resize --- libsrc/meshing/boundarylayer.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libsrc/meshing/boundarylayer.cpp b/libsrc/meshing/boundarylayer.cpp index 63c90ba9..a9407248 100644 --- a/libsrc/meshing/boundarylayer.cpp +++ b/libsrc/meshing/boundarylayer.cpp @@ -133,7 +133,8 @@ namespace netgen // create new FaceDescriptors for(auto i : Range(1, fd_old+1)) { - auto& fd = mesh.GetFaceDescriptor(i); + const auto& fd = mesh.GetFaceDescriptor(i); + string name = fd.GetBCName(); if(blp.surfid.Contains(i)) { if(auto isIn = domains.Test(fd.DomainIn()); isIn != domains.Test(fd.DomainOut())) @@ -146,7 +147,7 @@ namespace netgen new_fd.SetBCProperty(new_si); mesh.AddFaceDescriptor(new_fd); si_map[i] = new_si; - mesh.SetBCName(new_si-1, "mapped_" + fd.GetBCName()); + mesh.SetBCName(new_si-1, "mapped_" + name); } } } From e7b9baa93bb5ff72829ab32da489961a8a0fe52a Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Thu, 19 Nov 2020 22:53:14 +0100 Subject: [PATCH 262/384] remove another reference of resized array --- libsrc/meshing/boundarylayer.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libsrc/meshing/boundarylayer.cpp b/libsrc/meshing/boundarylayer.cpp index a9407248..bd5427ef 100644 --- a/libsrc/meshing/boundarylayer.cpp +++ b/libsrc/meshing/boundarylayer.cpp @@ -410,7 +410,8 @@ namespace netgen for(SurfaceElementIndex si = 0; si < nse; si++) { - auto& sel = mesh[si]; + // copy because surfaceels array will be resized! + auto sel = mesh[si]; if(si_map[sel.GetIndex()] != -1) { Array points(sel.PNums()); @@ -436,7 +437,7 @@ namespace netgen mesh.AddSurfaceElement(newel); } if(move_boundaries.Test(sel.GetIndex())) - for(auto& p : sel.PNums()) + for(auto& p : mesh[si].PNums()) if(mapto[p].Size()) p = mapto[p].Last(); } From a69cdc9000794a427a0176e1c63ba7cf423f043e Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Sat, 21 Nov 2020 15:49:07 +0100 Subject: [PATCH 263/384] mem tracing compile time option, simplify by MemoryTracer as member --- CMakeLists.txt | 1 + cmake/SuperBuild.cmake | 1 + libsrc/core/CMakeLists.txt | 5 + libsrc/core/array.hpp | 30 +++-- libsrc/core/bitarray.cpp | 7 +- libsrc/core/bitarray.hpp | 9 ++ libsrc/core/paje_trace.cpp | 4 + libsrc/core/paje_trace.hpp | 2 + libsrc/core/profiler.cpp | 2 + libsrc/core/profiler.hpp | 163 +++++++++++++-------------- libsrc/core/python_ngcore_export.cpp | 2 + libsrc/core/table.hpp | 13 +++ libsrc/meshing/boundarylayer.cpp | 3 + 13 files changed, 142 insertions(+), 100 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7916e6ee..26dfc2e4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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") diff --git a/cmake/SuperBuild.cmake b/cmake/SuperBuild.cmake index 37709768..6e9600df 100644 --- a/cmake/SuperBuild.cmake +++ b/cmake/SuperBuild.cmake @@ -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 diff --git a/libsrc/core/CMakeLists.txt b/libsrc/core/CMakeLists.txt index 8329a195..c3eba6a5 100644 --- a/libsrc/core/CMakeLists.txt +++ b/libsrc/core/CMakeLists.txt @@ -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} diff --git a/libsrc/core/array.hpp b/libsrc/core/array.hpp index 60132186..752f6f64 100644 --- a/libsrc/core/array.hpp +++ b/libsrc/core/array.hpp @@ -655,7 +655,6 @@ namespace ngcore /// that's the data we have to delete, nullptr for not owning the memory T * mem_to_delete; - int mem_tracing_id = 0; using FlatArray::size; using FlatArray::data; @@ -701,7 +700,7 @@ namespace ngcore NETGEN_INLINE Array (Array && a2) { - TraceMemorySwap(mem_tracing_id, sizeof(T)*allocsize, a2.mem_tracing_id, sizeof(T)*a2.allocsize); + mt.Swap(sizeof(T) * allocsize, a2.mt, sizeof(T) * a2.allocsize); size = a2.size; data = a2.data; @@ -774,7 +773,7 @@ namespace ngcore NETGEN_INLINE ~Array() { delete [] mem_to_delete; - TraceMemoryFree(mem_tracing_id, sizeof(T)*allocsize); + mt.Free(sizeof(T)*allocsize); } // Only provide this function if T is archivable @@ -829,7 +828,7 @@ namespace ngcore NETGEN_INLINE const Array & Assign (size_t asize, LocalHeap & lh) { delete [] mem_to_delete; - TraceMemoryFree(mem_tracing_id, sizeof(T)*allocsize); + mt.Free(sizeof(T)*allocsize); size = allocsize = asize; data = lh.Alloc (asize); mem_to_delete = nullptr; @@ -937,7 +936,7 @@ namespace ngcore NETGEN_INLINE void DeleteAll () { delete [] mem_to_delete; - TraceMemoryFree(mem_tracing_id, sizeof(T)*allocsize); + mt.Free(sizeof(T)*allocsize); mem_to_delete = NULL; data = 0; size = allocsize = 0; @@ -969,7 +968,7 @@ namespace ngcore /// steal array NETGEN_INLINE Array & operator= (Array && a2) { - TraceMemorySwap(mem_tracing_id, sizeof(T)*allocsize, a2.mem_tracing_id, sizeof(T)*a2.allocsize); + mt.Swap(sizeof(T)*allocsize, a2.mt, sizeof(T)*a2.allocsize); ngcore::Swap (size, a2.size); ngcore::Swap (data, a2.data); @@ -1044,7 +1043,7 @@ namespace ngcore NETGEN_INLINE void Swap (Array & b) { - TraceMemorySwap(mem_tracing_id, sizeof(T)*allocsize, b.mem_tracing_id, sizeof(T)*b.allocsize); + mt.Swap(sizeof(T) * allocsize, b.mt, sizeof(T) * b.allocsize); ngcore::Swap (size, b.size); ngcore::Swap (data, b.data); @@ -1052,21 +1051,18 @@ namespace ngcore ngcore::Swap (mem_to_delete, b.mem_to_delete); } - NETGEN_INLINE void SetMemoryTracing (int mem_id) + NETGEN_INLINE void StartMemoryTracing () const { - if(!mem_tracing_id && mem_id) - TraceMemoryAlloc(mem_id, sizeof(T)*allocsize); - - if(mem_tracing_id && !mem_id) - TraceMemoryFree(mem_tracing_id, sizeof(T)*allocsize); - - mem_tracing_id = mem_id; + 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; }; @@ -1079,7 +1075,7 @@ namespace ngcore T * hdata = data; data = new T[nsize]; - TraceMemoryAlloc(mem_tracing_id, sizeof(T)*nsize ); + mt.Alloc(sizeof(T) * nsize); if (hdata) { @@ -1093,7 +1089,7 @@ namespace ngcore for (size_t i = 0; i < mins; i++) data[i] = std::move(hdata[i]); #endif delete [] mem_to_delete; - TraceMemoryFree( mem_tracing_id, sizeof(T)*allocsize ); + mt.Free(sizeof(T) * allocsize); } mem_to_delete = data; diff --git a/libsrc/core/bitarray.cpp b/libsrc/core/bitarray.cpp index bc923ef1..6b1deac5 100644 --- a/libsrc/core/bitarray.cpp +++ b/libsrc/core/bitarray.cpp @@ -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() diff --git a/libsrc/core/bitarray.hpp b/libsrc/core/bitarray.hpp index 768b40df..cd8979de 100644 --- a/libsrc/core/bitarray.hpp +++ b/libsrc/core/bitarray.hpp @@ -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; }; diff --git a/libsrc/core/paje_trace.cpp b/libsrc/core/paje_trace.cpp index 4e5331e6..4e387ec2 100644 --- a/libsrc/core/paje_trace.cpp +++ b/libsrc/core/paje_trace.cpp @@ -743,7 +743,9 @@ namespace ngcore } } WriteTimingChart(); +#ifdef NETGEN_TRACE_MEMORY WriteMemoryChart(""); +#endif // NETGEN_TRACE_MEMORY paje.WriteEvents(); } @@ -930,6 +932,7 @@ namespace ngcore } +#ifdef NETGEN_TRACE_MEMORY void PajeTrace::WriteMemoryChart( std::string fname ) { if(fname=="") @@ -1053,6 +1056,7 @@ namespace ngcore WriteSunburstHTML( root, fname, false ); } +#endif // NETGEN_TRACE_MEMORY void PajeTrace::WriteTimingChart( ) { diff --git a/libsrc/core/paje_trace.hpp b/libsrc/core/paje_trace.hpp index 421f866e..c153c0cd 100644 --- a/libsrc/core/paje_trace.hpp +++ b/libsrc/core/paje_trace.hpp @@ -31,7 +31,9 @@ namespace ngcore public: NGCORE_API void WriteTimingChart(); +#ifdef NETGEN_TRACE_MEMORY NGCORE_API void WriteMemoryChart( std::string fname ); +#endif // NETGEN_TRACE_MEMORY // Approximate number of events to trace. Tracing will // be stopped if any thread reaches this number of events diff --git a/libsrc/core/profiler.cpp b/libsrc/core/profiler.cpp index 73aad63d..66365321 100644 --- a/libsrc/core/profiler.cpp +++ b/libsrc/core/profiler.cpp @@ -113,7 +113,9 @@ namespace ngcore NgProfiler prof; // NOLINT +#ifdef NETGEN_TRACE_MEMORY std::vector MemoryTracer::names{"root"}; std::map< int, std::vector > MemoryTracer::tree; +#endif // NETGEN_TRACE_MEMORY } // namespace ngcore diff --git a/libsrc/core/profiler.hpp b/libsrc/core/profiler.hpp index cb07d053..cdd945bd 100644 --- a/libsrc/core/profiler.hpp +++ b/libsrc/core/profiler.hpp @@ -304,45 +304,29 @@ namespace ngcore namespace detail { - //Type trait to check if a class implements a 'const MemoryTracer& GetMemoryTracer()' function - template - struct has_GetMemoryTracer - { - private: - template - static constexpr auto check(T2*) -> - typename std::is_same().GetMemoryTracer()),const MemoryTracer &>::type; - template - static constexpr std::false_type check(...); - using type = decltype(check(nullptr)); // NOLINT - public: - static constexpr bool value = type::value; - }; - //Type trait to check if a class implements a 'void SetMemoryTacing(int)' function template - struct has_SetMemoryTracing + struct has_StartMemoryTracing { private: template static constexpr auto check(T2*) -> - typename std::is_same().SetMemoryTracing(0)),void>::type; + typename std::is_same().StartMemoryTracing()),void>::type; template static constexpr std::false_type check(...); using type = decltype(check(nullptr)); // NOLINT public: static constexpr bool value = type::value; }; - - } // namespace detail class MemoryTracer { + #ifdef NETGEN_TRACE_MEMORY NGCORE_API static std::vector names; NGCORE_API static std::map< int, std::vector > tree; - static int GetId(std::string name) + static int CreateId(const std::string& name) { int id = names.size(); names.push_back(name); @@ -350,48 +334,73 @@ namespace ngcore std::cerr << "Allocated " << id << " MemoryTracer objects" << std::endl; return id; } - - int id; public: MemoryTracer( std::string name ) { - id = GetId(name); + id = CreateId(name); } + // not tracing + MemoryTracer() : id(0) {} + template MemoryTracer( std::string name, TRest & ... rest ) { - id = GetId(name); + 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(mysizeChangeMemory(other.id, mysize-other_size); + trace->ChangeMemory(id, other_size-mysize); + } + else + { + trace->ChangeMemory(id, other_size-mysize); + trace->ChangeMemory(other.id, mysize-other_size); + } + } + + int GetId() const { return id; } + template - void Track( T1 & obj, std::string name, TRest & ... rest ) const + void Track( T1 & obj, const std::string& name, TRest & ... rest ) const { Track(obj, name); Track(rest...); } template - void Track( T & obj, std::string name ) const + void Track( T & obj, const std::string& name ) const { - if constexpr(detail::has_SetMemoryTracing::value) - { - int child_id = GetId(name); - tree[id].push_back(child_id); - obj.SetMemoryTracing(child_id); - } - if constexpr(detail::has_GetMemoryTracer::value) - { - auto & mt = obj.GetMemoryTracer(); - int child_id = mt.id; - if(name!="") - names[mt.id] = name; - tree[id].push_back(child_id); - } + obj.GetMemoryTracer().Activate(obj, name); + tree[id].push_back(obj.GetMemoryTracer().GetId()); } static std::string GetName(int id) @@ -404,7 +413,20 @@ namespace ngcore return names[id]; } - void SetName(std::string name) const + template + void Activate(T& me, const std::string& name) const + { + if(!id) + { + const_cast(this)->id = CreateId(name); + if constexpr(detail::has_StartMemoryTracing::value) + me.StartMemoryTracing(); + } + else + SetName(name); + } + + void SetName(const std::string& name) const { names[id] = name; } @@ -412,49 +434,26 @@ namespace ngcore static const std::vector & GetNames() { return names; } static const std::map> & GetTree() { return tree; } +#else // NETGEN_TRACE_MEMORY + public: + MemoryTracer() {} + MemoryTracer( std::string name ) {} + template + 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 + 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 }; - - NETGEN_INLINE void TraceMemoryAlloc( int mem_id, size_t size ) - { - if(mem_id && trace) - trace->AllocMemory(mem_id, size); - } - - NETGEN_INLINE void TraceMemoryFree( int mem_id, size_t size ) - { - if(mem_id && trace) - trace->FreeMemory(mem_id, size); - } - - NETGEN_INLINE void TraceMemoryChange( int mem_id, long long size ) - { - if(mem_id && trace) - trace->ChangeMemory(mem_id, size); - } - - NETGEN_INLINE void TraceMemorySwap( int mem_id, size_t size, int mem_id2, size_t size2 ) - { - if(!trace || (mem_id==0 && mem_id2==0)) - return; - if(mem_id == 0) - return trace->ChangeMemory(mem_id2, size-size2); - if(mem_id2 == 0) - return trace->ChangeMemory(mem_id, size2-size); - - // first decrease memory, otherwise have artificial/wrong high peak memory usage - if(sizeChangeMemory(mem_id2, size-size2); - trace->ChangeMemory(mem_id, size2-size); - } - else - { - trace->ChangeMemory(mem_id, size2-size); - trace->ChangeMemory(mem_id2, size-size2); - } - } - } // namespace ngcore // Helper macro to easily add multiple timers in a function for profiling diff --git a/libsrc/core/python_ngcore_export.cpp b/libsrc/core/python_ngcore_export.cpp index 59d1a13f..abdceb0e 100644 --- a/libsrc/core/python_ngcore_export.cpp +++ b/libsrc/core/python_ngcore_export.cpp @@ -266,7 +266,9 @@ threads : int .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 ; diff --git a/libsrc/core/table.hpp b/libsrc/core/table.hpp index 8db44f9d..7471b6a3 100644 --- a/libsrc/core/table.hpp +++ b/libsrc/core/table.hpp @@ -159,6 +159,7 @@ namespace ngcore NETGEN_INLINE Table (Table && tab2) : FlatTable(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::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; }; diff --git a/libsrc/meshing/boundarylayer.cpp b/libsrc/meshing/boundarylayer.cpp index bd5427ef..89baa018 100644 --- a/libsrc/meshing/boundarylayer.cpp +++ b/libsrc/meshing/boundarylayer.cpp @@ -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) From 922ad16213970138b05ef21ab36eaee3786f92f9 Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Sat, 21 Nov 2020 22:32:41 +0100 Subject: [PATCH 264/384] if more memory is deallocated than allocated set memtracer to 0 not negative values --- libsrc/core/paje_trace.cpp | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/libsrc/core/paje_trace.cpp b/libsrc/core/paje_trace.cpp index 4e387ec2..9b4ac053 100644 --- a/libsrc/core/paje_trace.cpp +++ b/libsrc/core/paje_trace.cpp @@ -967,12 +967,19 @@ namespace ngcore else { if(ev.size > mem_allocated) - std::cerr << "Error in memory tracer: have total allocated memory < 0" << std::endl; + { + 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 -= ev.size; - mem_allocated_id[ev.id] -= ev.size; + { + 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; } } @@ -985,7 +992,12 @@ namespace ngcore if(ev.is_alloc) mem_allocated_id[ev.id] += ev.size; else - mem_allocated_id[ev.id] -= ev.size; + { + if(ev.size > mem_allocated_id[ev.id]) + mem_allocated_id[ev.id] = 0; + else + mem_allocated_id[ev.id] -= ev.size; + } } TreeNode root; From 7e78056ade10be3ff66d1a285c1695a1ef101c24 Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Mon, 23 Nov 2020 23:48:49 +0100 Subject: [PATCH 265/384] Boundarylayer grows pyramids if created on interior bnd --- libsrc/meshing/boundarylayer.cpp | 107 +++++++++++++++++++++++++++-- tests/pytest/test_boundarylayer.py | 15 ++++ 2 files changed, 116 insertions(+), 6 deletions(-) diff --git a/libsrc/meshing/boundarylayer.cpp b/libsrc/meshing/boundarylayer.cpp index bd5427ef..0aeb59ec 100644 --- a/libsrc/meshing/boundarylayer.cpp +++ b/libsrc/meshing/boundarylayer.cpp @@ -408,6 +408,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 +440,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 +476,85 @@ namespace netgen for(ElementIndex ei = 0; ei < ne; ei++) { - auto& el = mesh[ei]; - if(!domains[el.GetIndex()]) + auto el = mesh[ei]; + ArrayMem fixed; + ArrayMem 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 = p2; + if(p == fixed[0]) + p = p1; + } + p1 = p2; + mesh.AddVolumeElement(nel); + } + } + } } for(auto i : Range(1, fd_old+1)) diff --git a/tests/pytest/test_boundarylayer.py b/tests/pytest/test_boundarylayer.py index 04c0ee8c..f9310955 100644 --- a/tests/pytest/test_boundarylayer.py +++ b/tests/pytest/test_boundarylayer.py @@ -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) From d7a1dda0429d5e84d99bca6cff6bccb985e48cd7 Mon Sep 17 00:00:00 2001 From: mhochsteger Date: Mon, 16 Nov 2020 16:10:46 +0100 Subject: [PATCH 266/384] cmake - add version info to netgen.exe on Windows --- CMakeLists.txt | 2 +- ng/CMakeLists.txt | 13 +++++++------ windows/.gitignore | 1 + windows/CMakeLists.txt | 4 ++++ windows/{netgen.rc => netgen.rc.template} | 12 ++++++------ 5 files changed, 19 insertions(+), 13 deletions(-) create mode 100644 windows/.gitignore rename windows/{netgen.rc => netgen.rc.template} (82%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7916e6ee..9e07e4ec 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -417,12 +417,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) diff --git a/ng/CMakeLists.txt b/ng/CMakeLists.txt index 82d8ea91..82350afc 100644 --- a/ng/CMakeLists.txt +++ b/ng/CMakeLists.txt @@ -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} ) diff --git a/windows/.gitignore b/windows/.gitignore new file mode 100644 index 00000000..73a41fa4 --- /dev/null +++ b/windows/.gitignore @@ -0,0 +1 @@ +netgen.rc diff --git a/windows/CMakeLists.txt b/windows/CMakeLists.txt index e69de29b..e1ef0a93 100644 --- a/windows/CMakeLists.txt +++ b/windows/CMakeLists.txt @@ -0,0 +1,4 @@ +configure_file( + "${CMAKE_CURRENT_SOURCE_DIR}/netgen.rc.template" + "${CMAKE_CURRENT_SOURCE_DIR}/netgen.rc" + IMMEDIATE @ONLY) diff --git a/windows/netgen.rc b/windows/netgen.rc.template similarity index 82% rename from windows/netgen.rc rename to windows/netgen.rc.template index 047feb6f..6280e2fa 100644 --- a/windows/netgen.rc +++ b/windows/netgen.rc.template @@ -7,7 +7,7 @@ // // Generated from the TEXTINCLUDE 2 resource. // -#include "afxres.h" +#include ///////////////////////////////////////////////////////////////////////////// #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 "OriginalFilename", "Netgen.exe" VALUE "ProductName", "Netgen" - VALUE "ProductVersion", "5.1-dev" + VALUE "ProductVersion", "@NETGEN_VERSION@" END END BLOCK "VarFileInfo" From 2287c5c0c939ecd8434058d22f06673833f85c9f Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Tue, 24 Nov 2020 11:58:26 +0100 Subject: [PATCH 267/384] boundarylayers - fix inverted tets --- libsrc/meshing/boundarylayer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libsrc/meshing/boundarylayer.cpp b/libsrc/meshing/boundarylayer.cpp index 0aeb59ec..07bc8dca 100644 --- a/libsrc/meshing/boundarylayer.cpp +++ b/libsrc/meshing/boundarylayer.cpp @@ -546,9 +546,9 @@ namespace netgen for(auto& p : nel.PNums()) { if(p == moved[0]) - p = p2; - if(p == fixed[0]) p = p1; + else if(p == fixed[0]) + p = p2; } p1 = p2; mesh.AddVolumeElement(nel); From da4f959a0fd19796c8a92cc88e1b7a79b1e1cfb2 Mon Sep 17 00:00:00 2001 From: mhochsteger Date: Tue, 24 Nov 2020 12:11:27 +0100 Subject: [PATCH 268/384] fix license name in resource file --- windows/netgen.rc.template | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/windows/netgen.rc.template b/windows/netgen.rc.template index 6280e2fa..bbdab4a7 100644 --- a/windows/netgen.rc.template +++ b/windows/netgen.rc.template @@ -55,7 +55,7 @@ BEGIN VALUE "FileDescription", "Netgen Meshing Software" 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", "@NETGEN_VERSION@" From efdc57885af52d12f6f33844e9c06f6ead0a282d Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Tue, 24 Nov 2020 15:47:25 +0100 Subject: [PATCH 269/384] memory tracing - store parents array instead of children table --- libsrc/core/paje_trace.cpp | 32 ++++++++++---------------------- libsrc/core/profiler.cpp | 4 ++-- libsrc/core/profiler.hpp | 7 ++++--- 3 files changed, 16 insertions(+), 27 deletions(-) diff --git a/libsrc/core/paje_trace.cpp b/libsrc/core/paje_trace.cpp index 9b4ac053..1a1c9303 100644 --- a/libsrc/core/paje_trace.cpp +++ b/libsrc/core/paje_trace.cpp @@ -942,7 +942,7 @@ namespace ngcore size_t imax_mem_allocated = 0; const auto & names = MemoryTracer::GetNames(); - const auto & tree = MemoryTracer::GetTree(); + const auto & parents = MemoryTracer::GetParents(); size_t N = names.size(); Array mem_allocated_id; @@ -1006,39 +1006,27 @@ namespace ngcore Array nodes; nodes.SetSize(N); nodes = nullptr; + Array> children(N); + Array sorting; // topological sorting (parents before children) sorting.SetAllocSize(N); - ArrayMem stack; - - // find root nodes in memory tracer tree, i.e. they have no parents - Array parents; - parents.SetSize(N); - parents = -1; - for( const auto & [iparent, children] : tree ) - for (auto child_id : children) - { - if(parents[child_id] != -1) - std::cerr << "Error in memory tracer: multiple parents found for " << names[child_id] << std::endl; - parents[child_id] = iparent; - } for(auto i : IntRange(1, N)) - if(parents[i]==-1) - { - sorting.Append(i); - if(tree.count(i)) - stack.Append(i); - } + children[parents[i]].Append(i); + + ArrayMem stack; + sorting.Append(0); + stack.Append(0); while(stack.Size()) { auto current = stack.Last(); stack.DeleteLast(); - for(const auto child : tree.at(current)) + for(const auto child : children[current]) { sorting.Append(child); - if(tree.count(child)) + if(children[child].Size()) stack.Append(child); } } diff --git a/libsrc/core/profiler.cpp b/libsrc/core/profiler.cpp index 66365321..33ef98f4 100644 --- a/libsrc/core/profiler.cpp +++ b/libsrc/core/profiler.cpp @@ -114,8 +114,8 @@ namespace ngcore NgProfiler prof; // NOLINT #ifdef NETGEN_TRACE_MEMORY - std::vector MemoryTracer::names{"root"}; - std::map< int, std::vector > MemoryTracer::tree; + std::vector MemoryTracer::names{"all"}; + std::vector MemoryTracer::parents{-1}; #endif // NETGEN_TRACE_MEMORY } // namespace ngcore diff --git a/libsrc/core/profiler.hpp b/libsrc/core/profiler.hpp index cdd945bd..208b7a4e 100644 --- a/libsrc/core/profiler.hpp +++ b/libsrc/core/profiler.hpp @@ -324,12 +324,13 @@ namespace ngcore { #ifdef NETGEN_TRACE_MEMORY NGCORE_API static std::vector names; - NGCORE_API static std::map< int, std::vector > tree; + NGCORE_API static std::vector 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; @@ -400,7 +401,7 @@ namespace ngcore void Track( T & obj, const std::string& name ) const { obj.GetMemoryTracer().Activate(obj, name); - tree[id].push_back(obj.GetMemoryTracer().GetId()); + parents[obj.GetMemoryTracer().GetId()] = id; } static std::string GetName(int id) @@ -433,7 +434,7 @@ namespace ngcore static const std::vector & GetNames() { return names; } - static const std::map> & GetTree() { return tree; } + static const std::vector & GetParents() { return parents; } #else // NETGEN_TRACE_MEMORY public: MemoryTracer() {} From b55264e0ee6cf0f29bbddebd27a9ea83ff9bfeac Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Tue, 24 Nov 2020 19:20:21 +0100 Subject: [PATCH 270/384] memory tracing - handle multiple consecutive tracers correctly --- libsrc/core/paje_trace.cpp | 33 +++++++++++++++++++++++++++------ libsrc/core/paje_trace.hpp | 3 ++- 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/libsrc/core/paje_trace.cpp b/libsrc/core/paje_trace.cpp index 1a1c9303..bfe3fad0 100644 --- a/libsrc/core/paje_trace.cpp +++ b/libsrc/core/paje_trace.cpp @@ -29,6 +29,8 @@ namespace ngcore #endif // PARALLEL } + std::vector PajeTrace::memory_events; + // Produce no traces by default size_t PajeTrace::max_tracefile_size = 0; @@ -75,6 +77,7 @@ namespace ngcore start_time = GetTimeCounter(); tracing_enabled = true; mem_tracing_enabled = true; + n_memory_events_at_start = memory_events.size(); } PajeTrace :: ~PajeTrace() @@ -97,8 +100,8 @@ namespace ngcore for(auto & link : llink) link.time -= start_time; - for(auto & m : memory_events) - m.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); @@ -451,7 +454,6 @@ namespace ngcore if(mem_tracing_enabled) { variable_type_memory = paje.DefineVariableType( container_type_task_manager, "Memory [MB]" ); - paje.SetVariable( 0, variable_type_memory, container_memory, 0.0 ); } @@ -524,8 +526,23 @@ namespace ngcore paje.PopState( j.stop_time, state_type_job, container_jobs ); } - for(const auto & m : memory_events) + 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); @@ -958,7 +975,7 @@ namespace ngcore { mem_allocated += ev.size; mem_allocated_id[ev.id] += ev.size; - if(mem_allocated > max_mem_allocated) + if(mem_allocated > max_mem_allocated && i>=n_memory_events_at_start) { imax_mem_allocated = i; max_mem_allocated = mem_allocated; @@ -1006,6 +1023,7 @@ namespace ngcore Array nodes; nodes.SetSize(N); nodes = nullptr; + nodes[0] = &root; Array> children(N); Array sorting; // topological sorting (parents before children) @@ -1033,7 +1051,10 @@ namespace ngcore for(auto i : sorting) { - TreeNode * parent = (parents[i]==-1) ? &root : nodes[parents[i]]; + if(i==0) + continue; + + TreeNode * parent = nodes[parents[i]]; auto & node = parent->children[i]; nodes[i] = &node; diff --git a/libsrc/core/paje_trace.hpp b/libsrc/core/paje_trace.hpp index c153c0cd..5444a96c 100644 --- a/libsrc/core/paje_trace.hpp +++ b/libsrc/core/paje_trace.hpp @@ -28,6 +28,7 @@ namespace ngcore bool tracing_enabled; TTimePoint start_time; int nthreads; + size_t n_memory_events_at_start; public: NGCORE_API void WriteTimingChart(); @@ -119,7 +120,7 @@ namespace ngcore std::vector jobs; std::vector timer_events; std::vector > links; - std::vector memory_events; + NGCORE_API static std::vector memory_events; public: NGCORE_API void StopTracing(); From 91f127ef712af95377bf1a34ac3cacc639229e08 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Wed, 25 Nov 2020 14:34:29 +0100 Subject: [PATCH 271/384] memory tracer - fix memory accumulation of children --- libsrc/core/paje_trace.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/libsrc/core/paje_trace.cpp b/libsrc/core/paje_trace.cpp index bfe3fad0..56fb0c12 100644 --- a/libsrc/core/paje_trace.cpp +++ b/libsrc/core/paje_trace.cpp @@ -1068,10 +1068,9 @@ namespace ngcore { // reverse topological order to accumulate total memory usage of all children auto i = sorting[sorting.Size()-1-i_]; - if(parents[i]==-1) - root.size += nodes[i]->size; - else - nodes[parents[i]]->size += nodes[i]->size; + if(i==0) + continue; + nodes[parents[i]]->size += nodes[i]->size; } WriteSunburstHTML( root, fname, false ); From fbeb6137eb14492299d5355080f8ec31388aa191 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Wed, 25 Nov 2020 17:55:44 +0100 Subject: [PATCH 272/384] Fix SwapImprove2 Don't allow swaps if an adjacent element was deleted in the current optimization pass. Also update test restults. --- libsrc/meshing/improve3.cpp | 17 ++++- tests/pytest/results.json | 134 ++++++++++++++++++------------------ 2 files changed, 83 insertions(+), 68 deletions(-) diff --git a/libsrc/meshing/improve3.cpp b/libsrc/meshing/improve3.cpp index 3ddc0733..071817e3 100644 --- a/libsrc/meshing/improve3.cpp +++ b/libsrc/meshing/improve3.cpp @@ -3716,6 +3716,18 @@ double MeshOptimize3d :: SwapImprove2 ( Mesh & mesh, OPTIMIZEGOAL goal, ElementI FlatArray 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"); diff --git a/tests/pytest/results.json b/tests/pytest/results.json index 04cb980d..74f0e308 100644 --- a/tests/pytest/results.json +++ b/tests/pytest/results.json @@ -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": [ From cb0d8295bf9f527edc756cbb4f70c45b54151b57 Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Wed, 25 Nov 2020 22:07:07 +0100 Subject: [PATCH 273/384] fix hashing of bitarray (uninitialized value in HashArchive & random values at end) --- libsrc/core/archive.hpp | 2 +- libsrc/core/bitarray.cpp | 15 ++++++++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/libsrc/core/archive.hpp b/libsrc/core/archive.hpp index 2a006693..d56e3f7f 100644 --- a/libsrc/core/archive.hpp +++ b/libsrc/core/archive.hpp @@ -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: diff --git a/libsrc/core/bitarray.cpp b/libsrc/core/bitarray.cpp index 6b1deac5..1ddd3435 100644 --- a/libsrc/core/bitarray.cpp +++ b/libsrc/core/bitarray.cpp @@ -141,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 { From 7ae460b2e526c5e1ac72d3410bac8edb003e532d Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Fri, 27 Nov 2020 15:28:48 +0100 Subject: [PATCH 274/384] Fix .surf file reading. See https://ngsolve.org/forum/ngspy-forum/1275-bug-surf-file-read-incorrectly --- libsrc/interface/readuser.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libsrc/interface/readuser.cpp b/libsrc/interface/readuser.cpp index 29b16afa..f211f38e 100644 --- a/libsrc/interface/readuser.cpp +++ b/libsrc/interface/readuser.cpp @@ -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"); From 1c6051371e24e5b529eb276ebb03a5738cc1a6f6 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Fri, 27 Nov 2020 16:40:17 +0100 Subject: [PATCH 275/384] updateSignal for Mesh class --- libsrc/meshing/meshclass.cpp | 1 + libsrc/meshing/meshclass.hpp | 1 + 2 files changed, 2 insertions(+) diff --git a/libsrc/meshing/meshclass.cpp b/libsrc/meshing/meshclass.cpp index 66d28355..6234f1eb 100644 --- a/libsrc/meshing/meshclass.cpp +++ b/libsrc/meshing/meshclass.cpp @@ -6642,6 +6642,7 @@ namespace netgen paralleltop->UpdateCoarseGrid(); } #endif + updateSignal.Emit(); } void Mesh :: BuildCurvedElements (const Refinement * ref, int aorder, bool arational) diff --git a/libsrc/meshing/meshclass.hpp b/libsrc/meshing/meshclass.hpp index aab4e87a..3bdaf219 100644 --- a/libsrc/meshing/meshclass.hpp +++ b/libsrc/meshing/meshclass.hpp @@ -172,6 +172,7 @@ namespace netgen const int element) const; public: + Signal<> updateSignal; // store coarse mesh before hp-refinement unique_ptr> hpelements; From 657360818d5dca451e372910ccece2f8203f4311 Mon Sep 17 00:00:00 2001 From: Christoph Wintersteiger Date: Wed, 2 Dec 2020 17:51:47 +0100 Subject: [PATCH 276/384] rewrite loop to avoid index correction --- libsrc/meshing/python_mesh.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libsrc/meshing/python_mesh.cpp b/libsrc/meshing/python_mesh.cpp index 083ef684..1b1a35a9 100644 --- a/libsrc/meshing/python_mesh.cpp +++ b/libsrc/meshing/python_mesh.cpp @@ -1136,8 +1136,8 @@ project_boundaries : Optional[str] = None .def ("Scale", [](Mesh & self, double factor) { - for(auto i = 0; i Date: Fri, 4 Dec 2020 14:36:35 +0100 Subject: [PATCH 277/384] add contributors license agreement and contributing guidelines --- CLA.pdf | Bin 0 -> 23494 bytes CONTRIBUTING.md | 18 ++++++++++++++++++ 2 files changed, 18 insertions(+) create mode 100644 CLA.pdf create mode 100644 CONTRIBUTING.md diff --git a/CLA.pdf b/CLA.pdf new file mode 100644 index 0000000000000000000000000000000000000000..389f1dcdef18ac43b27f0ce9693deb2d27a71157 GIT binary patch literal 23494 zcma&MW2`Vt&@6at+qP}nwr$(CZ9d1gZQHhOpR@0GbCb>H?k4-Mrze@2q?4(xswPzs z5u;_KV}l|cDjw<{Y8}dlVj^H5us5=T;^Co}F|{*yu^?dnFQY^+W@+PM>O?PQW9VWk zVrpz}V#>z{=4*!xyDzacItjE>0sW;cEEw)0R zeChYGbuqW+`o~i-`|~xmC;v20-F_2}lu<^!0 zn9$M#862R^`a-R{J{|@=`b?b=i23N917O0wyFow{-82~L*eICBAnZ2=nNy8F-0?rB zFL3dI|Iej?(1dV8jV#nU3RQAww0%b)a%}%=t*1amO5ImS+GvQ7IHGwl$Ra-S1$jsf zcXs+RGuHdD&W``3#n)QWt#{i!@4knVT9thY>G99q z{mA#LGVCTy$zw>lL;v^j0>134Z0XJPw=Gp}rx|XSiS$p3n=7xiETXz6IyT zWrv=NZo{|y!ssI@*1&x8cj6bmdZse_dYOJW9g9f6NsG>WE(;5X*?ex?)5#~VMY~h! zHqtJ}aju6O(7q@)p>-fT<$iT#r&E8{S!3#w4oH$;dI)OPkCE(q!tzT~{p7g?^00dN zx~cF&>g>tz@am)+Ov&Caz}Q-Q2E~Jx*IS!dpIbp&K+y#?y|=+sKWHC@;sFOXnj`F` z=>+i3o`X%|9*%6Qc$T(fJ&7w{O-m5K0XoLe?GzDhKOb8{HhtBf; zG^SkP)xv*@R}0Ch5o6pn5l>*^#kbgdb1rtKnYfhDWLA zaseLhDmEIv_0qLsfXvm7!W3TUNmQJCv0Ww^6k`UMR13hNEHfA+`+gB+aLrlc z@%8L5vxkwl&SXO-T}G9d7O*%F3I+%Qjv;BGtEvdvQ8D_WCnQLac{n2JynSCdj;9hj z!j}5*%H*MpZ5(qO3aT$^VmoQJJu2G;?$pH(%o(|Tul$OZ5{}d!pRyblMJvp;N?sEr*aChc2*AZ4an?RY#lA7Lrg%R`b<;fD5ZKp1h z?Dzd^X+Br=t%KR^HudZ2>{cG!#%ozxe=XlU`V1GU-ZE*D_%^B`oSPH^+wNb5J>gMz zv)8|?d6cJHgc*pQ{aBbOJtcfA37D)dYYnQBlOn-vKne^243aFqFpYil5dg4Aqn>I+ z)?*}*E?8sD43o&BI56o#GWcH@ykQw%9ap$;ZDv&EQovybJo2^`SMK9yQ%Gp$u;4te zYis{kH5b&Ic|rqbp=*HbPDQTX$?sJ7@CaJR=ZJDTN1|muLaR7W#Yj$qVh1dvCtOVE z@j+b^N1P^m2|1oTqQ+!Ui2I8hnn-}eyKaC&p8k+#E}9Vn=l!d!dYkHiH@nmQ$q+RU zcqqJ4rf%v|eYh`pXcnR)*?-Qm1xWrk!iMOxlZ9SYr)i@`bRryKqVK>$ZW0847||BY zx?+YfU6_PT;nO(#^fLw^z>2kb5;+p=%cpu}Gm9C%|T zK~n?_ryBqq9OJ$!c2Vzb+7u~9u+uYY5@g;w;T=0-@0nynkBQoU zF~bh(woE8gna%3N`A}ZQUWkKfuaJ=hP8Fj=)8aR!x3v>n$W?NcAQVG3tT9EF`hcGR zy@oU&F>S%CCiKJ8=wBh7WgQs}vDP+Oq{~gWj?ABhYdM;Qg8|vdzZV+-=SY0$R8c)o zVCb*c-v8>h>)dE8z=2t)lwgM5()MmkBSg3~0MDqARvOua_U1bSVb!_rdQ zWLmf#2*O)lz;tZ*d2PP16$4O#E3dsj(M(rkk8i?<>Bgj}8CuNFVY8Nl8Et%h5Eiap z+r>nwRY4|GYm5J(30rh-{EH=`vT9Uhw{}Ir-&%`^FJC4z<%e#;Q9UgLXm5nAg84CS z=c(sM9C>J09C(_5^_DTv4wv!IUMaP1qB{x6As=s;2Sve*?20zRk}rNS;m!|_cQJ=9 z1T^#Nog%>HFcFl>)=9WflScIPwl&%2eH3jjLJ?Mf1#A;wA$O$E6e$WzcS4Uoa5r0< z&P7YIH~KSzbvh}|u8ufc7YUm!W|Qzvf%sOc&;&wR?&&1dLdi>diDjzr&uLuRx6hdH zZ-J#zc+t5vPh~r_;+7}rZwCxgtluU%qm>oTj?)8aUPS=E3!?3v$#5J$Otu&X zw*sN&IRA&sN@a3on{`xeT0vA%XKF9N8#p(ua$zqkgkuvgu$r+fvtwy2@iZ#6Y(|={ z*U%?x0iv2>&!P-85RN*e$q5!#a7N#*16%bq^Q8X#jftres2UTc2@X~0k;u9aq z#R1ZuVc!(RH|N?IaqzQK+%x4B{85pDF<^TV0F~@I3q-%_9Q0e05b(8Nd#> zG0c+Af*!7+SFK{|k7o3vZB-@=RBWucZGkIYG7wCv3L|$aR!g?{oN!w5Jx^R248=+? zHe1J(8}m`gk)(7?&Mu?(CZG&2w{qAot>&S`1LWIHWGe*qZIiLBmB^RmYOe915@#AJ zj=VurBRrwP5S3c6NMXLx)x|^2uM-icY@vG0TmA@%V@4T~(8T)|1z)dn zUJd2A;2dwcTtda3>@!Pc7knbVpR{z;Qd1{H)w)vL*tKB~t@))Th$%UDN~{RZU8T+W z{dR6)>zO7~24QT<%xLp4!p=*^v?B(LK~+;x&Hl;o&L1+)ZLVoJO0C6=c0fu{Yqdz_ zCXh*~u3%^+MC8<9CFqidiwlKH#-M=Lbf^n^skl$o5kCa>Y{FYx){Ld(D{8 z+I;2nHrE5DI~-ak@A_wTtkvm%3VRbI8pcu7ur;~B+XXcj5T0ix+aC*+PbJ<#1FCd7-9@fAr_4KG0P=S1Q{e z^@Hf`Y?@A8vkgN&D?cnAY_b5q6LQC=gG_)byu2%YW9o>q7fyK-RzH(a*e~ylw3@n# zvu8xDj_{I;@~{Lrhlj!z4*#L16_QFz;B**9LYVsRT0ZRBkBeG7>(2f$ew7{&vG6z}7XV^h=8tsS4MPn}FkD3`?l7 ze#2;W)KC}l`KAP2$Pk7SmP=g2l)NB_j@NL@5ZMC|s>%DCf@Cvv4r}&-VXHvi={WkL~{t>C=>r$7YA= z`BINd9K9l$sptxD7bjLk!T*q$ zG)fub5AOqKj8H5$t)GpvY8^5}LK>N}%kJ?5X4!x^l>I$YVPknM+10r7_g$WKgVIlH4HB((phptzd@92{u6`nTSrO zchF8{AFDA?M>x%oXYQqH8Ql<6EalpQ2Psr5FAdPF_vg`5Ai6D-s1QO%2{liylJrjO zEkUg1_>xSSX6gi!Iz(y)0JRYVY->LO9*I3b#fhE)FY187#S^A=xutGW-j?ckIhUe< z$z{h-23vOkNW=0fwH-;>8K#H0J7tx2U;u~$!l|o5Il*HQ=3EEu3AdDm*e9@=nNL>c z`*!7}gB+4pTlKy`v?W{QY8k-Oy_4j4VVR}nu#bq5)Xs0(V`$O98DSR9U)&qQ4?4F+ z5%tw;^gE{`NYNg(CxzArVqGY_M{WV!UT21=1iHbb6Sjh>-eRaq)EAG%b!4ruytQ{J zmobWjw*iy_Bzl@+$coK%SiovcpfPDBIluYV!a?+V5K!7MbaKwV)MtSBjE=pf+r8>9qq`7C=8B9D)+L^jyP)jHBz^{x8&=ZsEaHo?f5WdMYFiL7qqaX-?c7MYA zd89!O&J&fGJ&%FVHKH-GTZ+mUJWJBURBZ*xHMok|n=SC3pElCLnh$vC@E-6y1jwwH zus(o^F^e(E+F_y^D9_QpOagU&V$E(dE04o=7{(?gxQyv!aHA%YE5m`KA_}05cFK8y zHZ3kyzF3oZ(OlxgBV4`ak+YQ&0eJdqB9{n&VT8IK5L@_I^=QY`NCdqq}(=s+Cqf!EpurEuA%7 zkZd023a5w-T#{iEQx}}O>ah{sCDgm9o&gJoFz#z4E{%SOtI_ysF0sEluCzU~EPK*{ zC_=IilFl#_ReS|kNywyr1~bwAqx1;tZjH3RCPzyC3S5cKh59r> zOToh~%0ErYJKs|*i&>|{J-KD1tX*@^*`2i=IK#C;hnpAQShi(it&^-B`%%f(L4G@< zw^xms5MW%Ss5@>#ze8=~s3{to{S^grjq(zrx?mXDR*w5XsN12KzS>uk$dJ;^T$UiZ z|JvMcSAO|o5;kV{0p{WQg%)z5{JaGE)Aq#DWoS&IOM2T0Y=71XRv<}*!Xlb?98lR~ zeYv}{AOA?nucS-DAigd)*6xL+VVaemFj-Tp4u;x+W1KG3rc&m|SN1&L!d-NF=M;-c zZ}-6pNZ%!$Z>bmMY$+95KHP;To{qupqu?bA4Jz-*nVB(}^w0%IW%^i>R-BxQMzi^k zydll1>_hQ5pJuA*d-{>`#r9`1%KZFOsdr_h!J6CYmPF9HaEX+X9QN0C*-SAiV&@jZ zf@L$yYw{Gxv`a}hlF%yW^F5BzUx z?q~vIisqhsZ)G>PmzCagyk8$X%Ba}bSv=zrY6L+!sV%ji7ccCxq7b{LbI zs((mve-QR9m41RZNu-%}ArRkU@-!OF)t3i}?BRsN_97PRp;qxzJEraDA{0+-?R@{T z@)WLI?!O4W@pN>z+MnAHTTR}7zzf(d65AGEF0%eKV-;3G+x^^YtSxbhVIxxM*S4-URY;E?{tLD)AARuUSRV+E1|zJ-+Q153$bPmJr?}MI8ZL^ zu}k3Gqc$ZjrczMzTwS_++1+<=!<$RxOZXuD)*mh9ZF-l16B*jIG&*R;@BOA z_P6a^0DEAG*9wnJ=;QBEQb5fSxriOkiRi?^1I6H4k8pCwiF-5n$I~BgzBzwMuqM9V zlYKz%hBS{24NL2>cR7z$XT#zOF_z=@#Q9t@e54x35&ekl#qN@mP3S){)BwGQu(Idr znsGcDjOndT)0|5jPF)X3Ho@rWb@(IQ_uB%yhCEogVsFWL*fDSV%LHqW&gm^!DbKP7 z=$qQ9_WxW9T#-)gh57Ix%Nk-->?m@8Zw+fcu9>4?kmZ`zK$l^t(~ESCx-8a4hNx7G zyB?_9mA7Ly=eLf*oS;3y>kf`Sc)v}WC6@py1hNBO*|@~32d4zwKDFd3oTcBPy3u_n z)z43XZ`3P9>Q4o0QAjF<#P@qdnge8v@39&IIZD)v<|TJf_;62wL3eHlScUYGV$lW{ zoSNZr1%@Q3H$hS|x(_7|=oy^3{{Y9kA@@dpKyyiu6`?8*=Yne!aSPQ#@>U{&(FJa=qPVmTXzl<2=IG+ZYAR2ui1Wi0z#Dooh$38y#cMQ+I<7ybAMe}nBi z-v{cKD@dDCe|SHTe^j2R$p$+bHykAV2P`@A`4e@EqHocW_WK5-exyuWoWf7y-WS|8 zc#6UUHx*JhC)FXl2(T{{+Ly-tV~6V+NLZYCr1-rmpRi0gS3E13iPy2LWg}Wf)gH>X z#EClj)wEqt>w0YvlnH+01?k3-!C-3dkm9(c@0A?#A@nAj!Nhg2`r9Jmm#M8V%KG9C_|LH> z{qJ32#=WLW;@{2g(Yd1pUSxe}LK;di$syUak@AZw`Jy;yW=3x3 z@M?X!9x2L2dtq5IlN&9JBBTy$h9&HuyBAT28o~qGglchUaEz4Pka1lzQqaXQZ&`0- z5*BJAyy4w!JXsKLYv$Rkt<eHgm@w29-=8|x?C_b2*pjo64rz|K0Vn>Kbn{-2X#U~#9 zp=W8#5>8Yz^ieHn2qw)EJJ_@%&YIr~!N%d5*C`yt%ErA)^_b;7YW7$d$Aa_D800U? zJG_y#EWf!NzCz|h-uu8;{j}=7SCOaA4_?>2(|yL$>+UY^yaDqKP&?xK9ykHo*HfJ3TTiayAimjCP=H+ z3u-IbzShaesl_%da;~5wlHr*_H;tEW@-KWve-E>eveAP<(cQ1?cd6xBu;MT+CG#oXOnwL>uXbzYAVJ!Ap_XNHA zSA5%=AvmPxb=cArIiByGrBNLsR1Ff1%eHK2(`JiP+y<&EZWH${NV8%=){ryjFd7f9 z9hVk8(`i zDOujGH^BDt1NyJVFROXpCtA?ib^Y zW^>XI67{|xRTdLdE?Lw8ic~06fnFydg^!+N3hU2_8|A*wZLwob2!{0uRYF9cJ2@g1 z-2)CPP@oTjoCr}H5$UObpqnBBC`CL_oNKD0;_Kvb1Gm22c{!)z>*hrHjeD}LjGV5A z#cFmzA+3hV`LkR9u}>3)<1TNS7G!^My5>a9;mxUwBa*I|+-n!GgEuGSDUt%QECEF? zu~Cr?Pgd*+QwcDLO9<)%$guG|#q3|E2VCY*x`b*u)LH_TU!Vf5nuKgQB0c%k2ibv| zBdk_1djjk?m|@L&l-7fq9d<|lf6^w^Eg~NBn>4-TopgG!V>6WLg{6bu7gR6e-g}gn zFuMMNu3X-CXAQepa{t>9!CXi-9@Aa2cJ(`9bG$tyC_4OFXr@Bg4w4+Qthv2SkhD1t zOjJZRvnKn|vj& zaKctMKwjXeV$}o}jNoV7U>xk=P2$!t!fe|`f+C7gbP>f7D@q+|-n!iIO5`4*PTJ4L z%HRr$0!_F}!zAEU5`2EQJ>U2R_qm;-d`&+f-A)&y59T6nuJ-4nvsv75cJ)iQ3i0K- zeb?cWUEpm83;cW5>=jgQtfQFgDjIB4pW$7*kWM3Z6yZ=xhxz@vg=4<#4Q;*dxO59o zNHCKkP)?j-^ChB;h_{8uM-}g{5c4cOKj1$o{8P8LcDGv}L-e-qt5)(VD*6Ooi6OIZ zp>jqbDF>_$GzuDyq!_Vo2x=wS98lUTW*5>&aSLu&ooq-@ZTbta1cjWvz=@8-{M7I7mNh@U$EHKe_}ME(|L|}_$I&65*JR;vKbOa2apCY= zTpkP<<54yquDp*L^mi}ZcPXK>@0Q|eeW}S$DaiY-z_vP98w`;TS&O?W(h|fZP4bPS z$K(qCd@KcNfdGDGKpS9d$%2#uk|-5gHO0kmQIYNbpPK zrQ|X5os^}VC!CSbv)6??HDUc9Ow zj!d`|cEDgqo;#I_Nmytv@nCevw%kuYPm{X3_p%Fp@Vf>>$4M zq!ZNrWlVqCdf{cS;it{;9vttjEo|4+#T<|9q`0r)U|Gwg*nAESO28;_##j@jEap9w z$N+6LNg#@xH=HWmVsG2zJWOkn0Pc9_`z9C(AV3to#3-oy8? ztj8M+ERhlSfA#>4k(uzfTv?)bVPUb|+*znUuHC`KJ$j?>dVy>_XdUtYO$eF{Z&g;9 zxbb)&K*u-ScN+NK!XWEj25tDGT$cxr7^1NnxFbm%r<6!jHt(7PN(UHaW~dsRBZlM@ zbdY#g@TnmdpK$~u_JwKeccT&$e{$&YE7RkTpPv!xW>q`xJLmN8KI?YyvR|__w4jd* zn?{cbgCAbdu8S+;29CTH2yKPGpznRLFR)nHZ3-T=xSu^qFb@x`F-ZxC<47Jff+_T3 z_To{wX3$P;VGJkcJ|w&rj-^O}`NuPiFp-xJ;giDw3M#l2i^uET@I^!mi54)piqqLw zH5D-#F&iPRa2B5D0^RkSWzv#dH= z7uj82NqaH0_`H9)zqmgn>O3j~s)VSOuamD-uOeO-v4_Ykw2{bdzT3~@R*Q!z;oMSS z%#69`yfIU*9evl|spKs%?)CLSe3jp``^f&VZ@jz zRA2cGyumnXhMaU6OS{zu)i%HUXf{`Q%;y`^ z?4o5LSo;8;#K)=Yx1HJ<;BrumG_T_yKn=vI|mK z+dqO0s{}+SChcH_gb6Da!cSAS39t#2{!TUwLER)2l~?_iV&WNIfa zVUk%Z0ikHmBD|Vr$;3wroJc2I77dz{z#T<%ck?>heSI)K6y$D50nS2%T69{V)*#x! zz@sm{kCWb`%dboF%dyL^!He5cX!}0j!0ip+;7>Y&8bS{S0xjD3C^T&%0$vkTMH@UO9?q3W?0ogM{xsV4>-Or-sp9gpw!&g*x_g~!uud!=0Y5Uf6I7rWu9+)$x*igQz5 ze7Y-1ju2?{I8F$Rh00_XplfqdN%6KuF$`F3P2)To2N0q&%U~0haW6^h&%xaZ6HZs6 z<-NUWn4eRGi(noU`7Fxm52a&~z+el3Mp-#Du&F4XIBas5bmn6syQ~Cq?i0@XqaIBS z0`+m1J@4#!n(74Y4m3ik@aG&6fHi1<7t!h?L2@qM#ivFakyD4meO#rC1tYb04M9ZI zT%wUH@F_^Jk?M>wry@zVd{Pq$;%CmVhfx^j9b)-|93Q^xkEdZC-Mr(JoX^NdmZGI= zmbp_iDd!l{Qz|<^$A>4u4b)Dki5mAQyCI}z4EnRQBvPNEdKsNkZK4%v>DZZ3vnMS( zTupfIbJkC8nCxlokKEI;nKkg&X`8L;u?J-N{RNIQ;!j7Vor21`%089QCH<}Ur{^73 zm3kLl15Qu;kCf#`-&jCW&S24IVR<#Imqv_I;%>N5Lt>8INM&-G%ZfIyD@h+W2Q>rYRzR1!ofh7Rn@5 z1khYn6i|P2(0;c(5IBjrf*LQy{%(o|yVyXZDrNDStgl?yn>9W70;^TCHU<@6w9rtbnm?5L+@Q+&n3gU2J~ax7&7i)|FaGSb7oTW`H)eg!4njtcJF@33BWRQ|VN z;E9Qq)O*-2hd} zG>o$t2!lwsC$VoHP9#tcBP3yzpH9@YCUani!HTu}Vf-S)s=WCw>H9V+ux17yTwLE= zC_9w`|AsR2e2Tl9wW|JnPyo;>VFU16>ac?|4q{MfHmUe%4_pDthlpv=s|-UK!7w83 z8nJ56voXk1y_|kKR-6__4PUmVF60sD=LzW^FM}5$1f!KNZw`>;Q z_&^U0FpaSQat>$^FYm}Up@Jp)^;oA24Ni$ZH4IAa7p78uFifSkU8qQI`PByuro-q2 z-4k{C)RFZP&MnxACrrqwl5fqE7K+Hcln7Zh)3?08MR&^C4JD z5=Du5ct#2`iD;8z1|9Jym#~Ti6o`*cO0Y6ZxEmuU=W&{TW@mu8>E$`b|1{UqlJ<>f zg57`KKzEBb>_3ywy%$N8xptwPSvH!xCp(uj9(R~8^gy*Pm{Phhm@&3($eJ`PncOU%HiTLNPJK$hTx zS0PGU&*5Qce18u5x~7fJNCTk{ghDttwdszbLV?Q5*PPd&nU9e=;;N7?b9YTO44$*H6_E8tcjVF@+o0Q`W)5pQ&32S5GkZ1r zbo6Z6ciQ8$=>=j%wI9&zm^WtmDYof%>%0Y=O53p9v)qezJkZ;sc?S3idFc3Ry@fVS zeKx-EF-RMKU!B#N)2FI9bFd#J?So^Ria{yeCVJ~lP2H7G}xi_al38bX)@aq~o z<-Cv0L!htuBzcx!(6Fr-cct%=LqJUv8Ny8wx`MmClU8BP^GPmrTfmdu z_eL~&p6T`@OD?@$So@K$?wJZDY{7B9BRAv7j~s9U$?ufv)ZNRuSFRrDc<}Y&ne@(m zZ=Cu82NJ6C9nG#taRL9xcmV%SCG*CK!4Gh0y}Y9>O8{G&hbzSs3C#rIppR;fZk&n} z%{9BfEXa@Ht>fIbzKqCk{5HUB@MgAGTF$Bh;aJdnV;5jX!*62f&sWGmQC zN#0KC^4%V1qL*!VJnyhSU}Lz}-EI`@t}Qy@yOSK}<(IFtcewh^fgL>G{W`1}+Ih`= zxK^pxJ-j79n6>81d!zBr42*`HeX)_TXtB}+=a$0!!4}C5$_bjxd>PyKQs&$S&2Sm| zUdR;?55$QJBIi69mW!^ot*afPeNxd$L;-%`Uh;|1N1ou>SMl|$MGzVI@=CP z;aV+8Ga8WyGOi0eVO(Vxl!g{zl}{C)mWG8rJ2OOpJZyI-HmDJD2fl2m@`(BZc<&A? zce>x4_$F_WFU5KHzrB9FB%itzpz&Ia5;>w_LK>FJpj4dMR___iJWvB0T?&XYD2t?_ zK|pFz6dQDZ5Y3JjbvclgDgF94d)uffv5&m3}dLYORRdBepb*kzX{)*U|UID}H zmjS>z^y}3xTgFld6e>w1{1@yP}P z^4(M3*t-G8pJl|gawOCDok4uzYk81(%{^EqExxpnLmBoi+h`biY$6Qg)j2Bkr^OoE6GD4OwFmFC zIfHxi_>AP;y0hI8LI!%vK3sDapp?nl9B7VxP)hc59s0k5vyo#ZCv?DrEQI?8Q9_wW z++$>JDbJ-oUx(u~sONUKh4XC&*|odSdS|`(KI);z>2b-Dfv%%`|`EBRw9*x;@DYjasSTATFoVKa&G1%+OMwUUf&E&P1 zx~$ONh5p!$bYG3dcpAGO0Gr5fZa4p9y$aLKXLIFk^Hf(-nkeq*C9s@eo7;}v7_!cF zzl)3tYB~{BotlxxFYokQVy$@jsB#k{Y}NmWa1XZqHy=Ce!KY)cYaIz?zqGMMgDsP=EzM(gTkg^pL9r_|T}kb2oczw^DEZO`YrBYd)a{RRqJarSrBx57_7 z`C!ciXS?TT;Xw5GmBs+}&R(EWrfYSOceo&>2{MKxc43LgWHmyVyrUNs90N>BR=qP@ z9IKvX6W25GbCzxYIvnW#Vso~wE8MZ>?L={-mUY!XMzjEDuB71sf{6l|4K?hxkrrO9 zEo1xY?YTTk7(H#s$+RpqOriCJbD|=;2JRx#+#_@*O|SX$aboo6fWkNSMNC^gYixcB z<5$X{>`v`pRnK9hn-M4OgMmLQ4v`pZ(Xftk8*LGz6S^8!1Er7JK;;C#iEJ23AX9+I z0TgTUyXq|*P}WOE)E(&E(KQ}^H|ZqnZF3`QPv7&he9dp@{rh5gInv|(MmO*lSG%Lt zUd(Dg7-`M)_dJD-R}-(qZ`|p6^al7^Tgn?LY{5MyJlW9g9mM-NHhpnQ??1N>(*Nh=&ZvbHBi0QrXj59ceuhXIN1poLgPL~0ZRV+0^Qr!xB=yRU_PMh70Zx_GUSr5GTYyYR6 zhCh1Oo0SlCuHw3gOay{59ub&sw!mGDQBe$$Xe4_U@W{Y0igj@mZwc?Axch%UwKI4< znLmuq1BPoqAs7pYteCR`tX9yiKqmqZ3h7~?2?*WjQtXl}vm>hAU|SOFdhreysU}Lz zlEft0zez(@ZC>9`jk#DMp*Qhk6ZciT7FhLeqzF~UuvgWE=-GqnoQ2NoJ%qtLL~Yam zNTXAn#515`a6$SxvS1^|M0_$~n(U_Xzs=XUNynETT$D?%RrXxT^BO~5a&C?;It{sF zB-bc9MYZFDPMeOfu2}6_ZL+$3wF|Y0HwQuF|RsM`pa&%1s{~TRy6s+q7|YUE$CSyWyf*_+~yn z#fLl1JBNfN0k?uwEqw_ST;Ur{z8cjC&l+BjzE38+x*hvHkcO2>s~rQDElv&%kOJ=)>E_Ns5AVxWSOf*~^Nh4z-q;q8)bnZE;xjxtY8))3J9}ccKc_;D- z$=`Mdoserkf~;)z`$)zcN1!;6Mc2C{k?qZ$PwVX#7gv zOHZ93;wU^4V>tfrdFMIa=X*mt&98lt7wMO1&8KC0zAupF?YpX2=bjpW6aZFTFb5)u&7UC78FaOtdUmNxU-f+ib_)-Y(0ctu62T z#fy!#JGCtDJN-YTd-Y#AHEjUPFURQRL4Hzbjk$to#b7#d?>8Jwa3h(Y0cc;7u zGStwoN^cxmQ&4YjzRjugJHXFpPAEiGE^tV!QQ-P4a)BLEAYUZZNG|C&NdB-cpuvS^ z$bI3l{&2Vppf@g?CQh0p2SV`-8XAJH1wX|zajORoH+avAv!S+z&1BM?yp5Km-9qte zd)9XB|D5ZKp&NG4*dOMo#PvOzZsa3A`hMw-YDT{Mf^f9TA}*=<{gUnToNKo890ZWek}a?dt>?tHiNPMG`A`8)<`c; zuX>Z1im5L6F8E)>O%>yk{f*iO9Ks8C90oZS+IQCNl4MR!6AF$CCIsEJ!8Av;S~cV} zVpp+i=r@pTNn4`_P6n#3b9@tgi+)0kBaGvZS`wxcR0+X_dLOlG0T^hm_X%wm%6#wu zq=|P2Li^c&wh|n8YS((--Zrs>eYWrTPYt$-e~p38@SpIX9DMryX#{@#cl~Jwdp|P% zGHxyQUh%O3;`3hcvu*f?0{h6AiVg<2zsJx_AbxB9)}!9{-wZ^juL28W_Tj(BFhV)1 ze~sZJ<4FD(1D`H_jq&21e#R1Vao4`$MNQn_zsHcGoU5PkvF9zuj(&}m2Q9|Le~p~>XM9@wNVSv=09(^q zIIIMoR}gSVfG!Cb7o4e-EL62$rcu5aFl6lK?m=Kx0iw32NEv8_CC0Ag1>{jt_q4n) zvn zcvfMh2YenWVUYhf?FUxZRk1iU-fk^WpYiX)N!@!VO6-yxY!3DJ_XI$FS$EKY)5u9b+>0TQmS?CR8oVx~b*%N0Bl;xJFRop!R++-bAxzTEo%)Pz0fY}J7 zw1bUb)ByKcC|LEt=2b=2u+UY#sdN|=vcy&ds$1($5oj57c9m9!ab;O661U^w04Sz! z&5*3AhyyRL0Qj)dI_u<w^e)bL|-U3Gb<8vqKvk9 z4bXsusdiW0z19K<62w{cG`+0!&sT=kfI>p6Ki5%kLs& z;+~nkuD-n9N3K#wK|>FQC9p$@RGo5ymXZeO-$DkYaU^sEw4`3@ zx7h~)2tqbPkEyKLVe$A;B|`;{T>0d2aXa#3$w|7bluE#cD?+ETp3t(NbY9`nd~w1w z**Q8YrF-zP@p18c+tP(*Ww!Y6V(IZD=z=+l{4@<+j$ZBYQ7~n@`=3uNJA$c@qTNBW zimB0U^R}c)PCt=L2ANzwmkF1llAoiWrJZ7>l3EgfVFF$N9<=lmc}i2_f5Y}7h{o=N z&xeiQS7!Z?80Z>As(GxO`LuvQ$AkX=S1s294fXc@L!}1kQhG?HG`bPp@6X=nJG0i=((7Ff=Nwn3KiiRQcldQzV#xs;`CyH{9_M&qTy5 z4cCFw!W=weGRW5JUqx$ZK@WmNV@+>j_wLmRsf zEy?ek(RCfl_uM2G27bE=>-B!{N)c+y-BJ2h_-0*SP*%R6x_#5=J!IwEB> zCW5c*lem{_g`wQjXu1v4_#m=#OtO|jS)$Bc+WRd_Cc0)Z!XU+&geZhh9$-ZuN=0jG4o=GLWr-AT6%?izSEq3e2a z`!u=Nq;l^EC^m#y$!uzh{tea;fsU&e9bL}XR5gz^ee1d9dc-H1cS@{G?S9SN>hj=` zbkTczP_F3UI}VrUJtssEXI?7$3-`J9c5k>l8}75 zV^Ck^LUfo)Q8}qv&u`da>Qh+SUAL8|bGyFyuncz?oltH(YKYIY7U>?^z>9l&-dse& zbNS>Fir**d;mRZN>hkUz-)Qr;NzCV@=5vdBo-Wg$ukg<$Ho85RJjUhi&>%v+K3=PK+&2eBkcU@S4YBsRbw7@~Is&cWa_PnKu;$&M{Sv=66gNo*%kZ z<)Y$+Z+e1b8&iV=GbV?h&jqnh(v**dyXWwpxX;uV4{~B*URdTE|7+I8^{s`UJR!N`w;1q1}U{kuidWNnh;+UIC&a?WWr4we$^ke6e zQhFPmcraYC$%1Sx8$WtgdFuVi^LefZ`=Zt=^^7bb(iJro#w(`1E0SzGyAo@tk>+fi zm9VSP=~Gvd5l=<0TX)eWJg%gj8%7?~h>8-j%kz2ph;`;gi`vBPv>vmvie6;Im!tke z#QLNc%C2gSa9B>k;|RT~y5i38u0{Vmk+bc$3r8mh_3Es$yC)6GPrlEY+Euvvk0_UeN1&;p^vWP3wGp+}+IYN^T%S3B(d=F4v!)v)cfgz-(*jc;xW5b-!t zB+uie?6{vhl76A(;gP3$ymJxZ!$*n|z<*>zw?1zr6!*)PR`zyR&$rO(N^l zWRNr5PPKURX7>4U)DB@~6$jJGp1Irk9S?8YRU)&uJgm^Dh#MZD9)7yU*3!Pe?AYh2 zz6!3qsL)<(aVw9aOK8c%4HHKO68J&KXq}CZG1spK=&`Fjc8fOGTg9cgr@dV}^OKxG=~w@vMe-~HklZd+M8*yn3OS;nR|9LAxV$Dr(meF!#Sm;D!6vue`Z!O!eTBTL|Mg~+2@;{H!t>mP{7Q|g#I~HdtC(P&gxL9D_p{2>j=cEa zsT5yfZ}Uf?ZDrUuRZHtq(INeq3_LwHLwuRHZ89R;=Yq9XpPO)S`u!KIN88@yXVJoo z%sq(fmr>u}ZgI8r;6~T>dCMzLLd>7d-RbypVJ5q$in$@VW`!Lrxn@&y3ic&m zcz(&Nuu((DHNW#P?RDac_NwgEWBl9fBQ3H#EtMWfVxy-RW|34=tY7Ik@+O@llLv zqn&7e|7?g-`g{6?H66xf>lZ^z-DK(~*~Wuc%hZS0%@)eOxtdjYBy?@zQ^y-;TJ+vw zY|QV~1g=;VQv?GCVfsY1i& zGm6{gt8BfZ<(|uV98wPpnr)3vtE$*@kliut^5w|GuzPmqe^N=UFJleUO7cVS)vtNG zKCOB_(3WajFm-jRXzexKkaFCS_l|DiMg3K$2sM>jT&ofBVe9H{OX~;mvh(#P8@l=O z`&)QHJ#JyShAe>`vF6^B#X+vixaCP(eNu1a4QDlE1< zp3ymbH^EdkPIXktL~iHclgiBZhxHC8#24)-3tl_uGe2Bqyw~4;ikBz9O>$7wHvaB{ z&pdqk`aJwycCRF-#%!+}oKrmV#LT`}0X0_TXHwkdkhDk*LA*P4k2AM8OPQacgvdoL zW`-aFH6rJ`CsX_= zn+f#|FnF2mvF}e_Vb!*r@K?F{0mKFJE5x)-dHzKEo0@=h0~d9F#M$YAfDAsnPc=E% zIz5k3JlisY;j+sbFVD5#F&yKyQB4;dY!x%!A5}Ct_uzJC`8l!f#lUI>aHMb1YBHX$ z9Hie+QxLF??KFC=Sac#`RF2EmA02!-xZreLKm6%T)7p0p@dPAA zUJcyThnB1xHP&4VUGtJ|s&^V{{OOV7&$^Y~mnPRJCKhA3i#ItnXSmrG%!7!#=Rl&=MW0>d@lDealu*%!?0{Y55O;tZHGpHtMj6j#V8(b!Yui?)cC&1bjop4}Aazl=S& zZsmiEfzA8*iOGw)!sKh5>{}cWr9eHzti@P4WvY^E<}${YUil!IKK95i^DiCY9uI{C zk@kduq&-T3hKMSQv1@T7rd$Qd%t(C<_o2&JVrF@5;!Vp^GsLb?mo@&^_^x`T^R+04 zs?6QDo3`#=uXoeBUIbHVkFc>ZdSIDaes-Ujp*sy>L&%I&;X0RP^mglhtR5i0wM*?S zqn-C|@#UXiJ9ni@`lQi#z2bIufN&Q+eYbrw7qErjfq~v2a!~JkeZ0|wvo&2)bIj~au(0L8I z1s9XL6Q7LGD?OxWq(mFpdQbIPt1kWh)=8yL*Do6*Vja0nO4e>o(lTjD8&l1B#xnO4 zlv0nG|7mHEOX<&lggT2wyil_ z?<}2hnRCLD!=or(cNQiZo@vz`JFie_7Gs9!v%q{joQY~SE|QbocEm%$>B*UsH=6fr zI-ia?ZD|ls(Tgh=%ehlu|C@}%<#VU&2`dzKZhNT_rJuZ0ntQhn?tGoUQG~mXxMG7M zhYqJboX|QODc+vkVTfVvJAvvjin{##;iHr)r~`_|8`Fyq3BE0-BXUf;GXwp>+rZ)Eg>{g>#4PVwO3nrn-qxX;3;|I0~N!4cMP zM_q~dze^*a(f=HFH4pTrBJ~(_mJZd|iAnQjF+f2)@M!GdMMY|9LLX%vs=I@wpP2*Q z7X}r}bM=MeKm#yoX)%u3sGw086kG*Iz`)T&GWfz^F}6qpmV+nFNt5pCNrj_eNKIcS zDxC!()q_%_iJ}S-CjU^C-AVd&+ZGdWj6mIxc4>R7VX zIq6n$%O1M^(AKsamEFPFD#>06Rei0y^Q}z_>gxSnS6$hlPSW%8;g^W` ziJEG>87J~}`}n;tFMV#G9`@seNVa@zoHMj1ygD|O%^4Z)ovxHGdf(XcVaMqM3AC9H zjL<{RcIOS3kEfS354g-c>kYnQTl_?I_s8@B54Y*xzkJFHcK7rA<5~Q_E`6*k&bnlj$|VK}j{zf?n}DOKA)t2j~2r4WgKDZ+g0 zSMKt7degL#@0NPmDfjtZ<1&Gb0jc%7igG58H{0+1pt^jHELC`PvOWvVVm6IGbkJcT#nJUMP5@IQhSY%lASepit!Bae*}Rb7Vn5V$SrV z3aDBRzElXC|1~^lOkb9^n*$R9y`jUmHUXgCissC6^R*$MP;erS1Sg>Ja4d)x0u~1@ zEF6m^z==d09E&D?rGX&D5Q%U+84V|pNpRfPXV`asJRbDn$Z$M}Jpu^_Cj(gmh<9i# z0tgQ*83o7T$$~p11C2w(qG3=UnM8u)(O)k}AD&1CW03yVjm2XG{3OsPm=_7miHw6| z$T%2*L;yOVxdL4nAP02fF<^Wm9*zfV6ZGN1oBRrTQ}bm`+q*IB+6FFrqrs z9H3kXl?=d>@v2x9mW(B$P(%`N3kio-C6UNP0+vW5gEVD})TGlHEMFTK5t4?3I13<9T^*?n)&eHu3m2H=hphO6LH@sH z{(qaOz)C+%6#cyf16Z;)!w+%|$lV}vzz!lXC=@y0+CRAl>V@{RzvWO!a~jK&x?4|I zPY;E{>7q~sfI=b;+=2O_HUZEu-}-QXhC!iFcr2g;8bKTIf{29pAUf_l9mqgq5CM@u z1{b&!zmE&#Ai97b$P4-*xo^6N-`awHG@wH;01twGh)3rKUYxpMJ7n2FJF+SAko92z zeXJ^g6%mJ11t5Z>Y`yW&O5-wf0#Q+b3a>2+X1|p zFkFFET|oc~0vd)q;7z4}oyJ#Bzy+?L`+0i81z#v&mjiw*PZ}KxdO;y6D818Ne|M&; zXqxZ%N#hTtL^Sz%5_}Y#^06`#Dj+^WnY&5&-Ty=x`9wA&^5C1m+(A3gsvaP>)4@R|!0!1Ii)) zuA_zl5JzKBI5ZAJz+se8=kfz!XyKpXup8Wv9kF#L%RgC^oZ;`oV%!s5Z6`3nt?#sl#F#D@W|mcPnkFc>_* z|4)1u91FB&LI_AeS9+KhgYC4+tRUo_IM za|X)*Vf70ih5+6N{-&{*4&c3+38hIhS`Zbu2x-b-fQO`ez-{2W z@mgqYEj?YV9vZKwi^J)nNhBRD5*i>tlc0sg5!GS;n+3`qIt(XmH>#6|ub&qjNhFYU z2zokb6p2Vg. + +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.com/forum). From e87b238060bdc2314289249b4485b7ef2879d40a Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Fri, 4 Dec 2020 14:38:25 +0100 Subject: [PATCH 278/384] fix links in contributing --- CONTRIBUTING.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f5bcdbf3..e96b1902 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -3,7 +3,7 @@ ## Reporting issues -If you have a problem using Netgen/NGSolve consider asking a question in our [forum](https://ngsolve.com/forum). +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 script will get more attention than unspecific one liners :) @@ -11,8 +11,8 @@ If you found a bug create an issue in the [Github Issue Tracker](https://github. 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](https://github.com/NGSolve/netgen/blob/master/CLA.pdf. Generally you have to sign this only once for Netgen or NGSolve. Please send the signed agreement to . +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 . 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.com/forum). +If you have any questions feel free to ask on the [forum](https://ngsolve.org/forum). From 77c87ba76ece00f4b3cf97d409d844b677ab3245 Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Fri, 4 Dec 2020 14:41:56 +0100 Subject: [PATCH 279/384] change script -> failing example --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e96b1902..15bb16b2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -5,7 +5,7 @@ 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 script will get more attention than unspecific one liners :) +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 From 2d667a08dc97da22d78f64000c10794e3a854dd7 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Fri, 11 Dec 2020 20:54:41 +0100 Subject: [PATCH 280/384] move (refactored) SIMD headers from ngsolve into ngcore --- libsrc/core/CMakeLists.txt | 1 + libsrc/core/ngcore.hpp | 1 + libsrc/core/simd.hpp | 69 +++ libsrc/core/simd_avx.hpp | 259 +++++++++++ libsrc/core/simd_avx512.hpp | 239 ++++++++++ libsrc/core/simd_generic.hpp | 597 ++++++++++++++++++++++++ libsrc/core/simd_sse.hpp | 260 +++++++++++ libsrc/general/CMakeLists.txt | 2 +- libsrc/general/myadt.hpp | 2 - libsrc/general/ngsimd.hpp | 672 ---------------------------- libsrc/interface/nginterface_v2.cpp | 87 ++-- libsrc/visualization/soldata.hpp | 19 +- 12 files changed, 1465 insertions(+), 743 deletions(-) create mode 100644 libsrc/core/simd.hpp create mode 100644 libsrc/core/simd_avx.hpp create mode 100644 libsrc/core/simd_avx512.hpp create mode 100644 libsrc/core/simd_generic.hpp create mode 100644 libsrc/core/simd_sse.hpp delete mode 100644 libsrc/general/ngsimd.hpp diff --git a/libsrc/core/CMakeLists.txt b/libsrc/core/CMakeLists.txt index c3eba6a5..8c8506fe 100644 --- a/libsrc/core/CMakeLists.txt +++ b/libsrc/core/CMakeLists.txt @@ -73,6 +73,7 @@ install(FILES ngcore.hpp archive.hpp type_traits.hpp version.hpp ngcore_api.hpp exception.hpp symboltable.hpp paje_trace.hpp utils.hpp profiler.hpp mpi_wrapper.hpp array.hpp taskmanager.hpp concurrentqueue.h localheap.hpp python_ngcore.hpp flags.hpp xbool.hpp signal.hpp bitarray.hpp table.hpp hashtable.hpp ranges.hpp + simd.hpp simd_avx.hpp simd_avx512.hpp simd_generic.hpp simd_sse.hpp DESTINATION ${NG_INSTALL_DIR_INCLUDE}/core COMPONENT netgen_devel) if(ENABLE_CPP_CORE_GUIDELINES_CHECK) diff --git a/libsrc/core/ngcore.hpp b/libsrc/core/ngcore.hpp index 72ebde25..37ce696a 100644 --- a/libsrc/core/ngcore.hpp +++ b/libsrc/core/ngcore.hpp @@ -13,6 +13,7 @@ #include "mpi_wrapper.hpp" #include "profiler.hpp" #include "signal.hpp" +#include "simd.hpp" #include "symboltable.hpp" #include "taskmanager.hpp" #include "version.hpp" diff --git a/libsrc/core/simd.hpp b/libsrc/core/simd.hpp new file mode 100644 index 00000000..277dd851 --- /dev/null +++ b/libsrc/core/simd.hpp @@ -0,0 +1,69 @@ +#ifndef NETGEN_CORE_SIMD_HPP +#define NETGEN_CORE_SIMD_HPP + +/**************************************************************************/ +/* File: simd.hpp */ +/* Author: Joachim Schoeberl, Matthias Hochsteger */ +/* Date: 25. Mar. 16 */ +/**************************************************************************/ + +#include "ngcore_api.hpp" + +#include "simd_generic.hpp" + +#if (defined(_M_AMD64) || defined(_M_X64) || defined(__SSE__)) +#ifndef __SSE__ +#define __SSE__ +#endif +#include "simd_sse.hpp" +#endif + +#ifdef __AVX__ +#include "simd_avx.hpp" +#endif + +#ifdef __AVX512F__ +#include "simd_avx512.hpp" +#endif + +namespace ngcore +{ + NETGEN_INLINE auto HSum (SIMD v1, SIMD v2, SIMD v3, SIMD v4) + { + SIMD hsum1 = my_mm_hadd_pd (v1.Data(), v2.Data()); + SIMD hsum2 = my_mm_hadd_pd (v3.Data(), v4.Data()); + return SIMD (hsum1, hsum2); + } + + + NETGEN_INLINE void SIMDTranspose (SIMD a1, SIMD a2, SIMD a3, SIMD a4, + SIMD & b1, SIMD & b2, SIMD & b3, SIMD & b4) + { + SIMD h1,h2,h3,h4; + std::tie(h1,h2) = Unpack(a1,a2); + std::tie(h3,h4) = Unpack(a3,a4); + b1 = SIMD (h1.Lo(), h3.Lo()); + b2 = SIMD (h2.Lo(), h4.Lo()); + b3 = SIMD (h1.Hi(), h3.Hi()); + b4 = SIMD (h2.Hi(), h4.Hi()); + } + + template + NETGEN_INLINE auto HSum (SIMD s1, SIMD s2) + { + return SIMD(HSum(s1), HSum(s2)); + } + + template + NETGEN_INLINE auto HSum (SIMD s1, SIMD s2, SIMD s3, SIMD s4 ) + { + return SIMD(HSum(s1), HSum(s2), HSum(s3), HSum(s4)); + } + + NETGEN_INLINE auto GetMaskFromBits( unsigned int i ) + { + return SIMD::GetMaskFromBits(i); + } +} + +#endif // NETGEN_CORE_SIMD_HPP diff --git a/libsrc/core/simd_avx.hpp b/libsrc/core/simd_avx.hpp new file mode 100644 index 00000000..92ac6c04 --- /dev/null +++ b/libsrc/core/simd_avx.hpp @@ -0,0 +1,259 @@ +#ifndef NETGEN_CORE_SIMD_AVX_HPP +#define NETGEN_CORE_SIMD_AVX_HPP + +/**************************************************************************/ +/* File: simd_avx.hpp */ +/* Author: Joachim Schoeberl, Matthias Hochsteger */ +/* Date: 25. Mar. 16 */ +/**************************************************************************/ + +#include + +namespace ngcore +{ +#if defined(__AVX2__) + NETGEN_INLINE __m256i my_mm256_cmpgt_epi64 (__m256i a, __m256i b) + { + return _mm256_cmpgt_epi64 (a,b); + } +#else + NETGEN_INLINE __m256i my_mm256_cmpgt_epi64 (__m256i a, __m256i b) + { + __m128i rlo = _mm_cmpgt_epi64(_mm256_extractf128_si256(a, 0), + _mm256_extractf128_si256(b, 0)); + __m128i rhi = _mm_cmpgt_epi64(_mm256_extractf128_si256(a, 1), + _mm256_extractf128_si256(b, 1)); + return _mm256_insertf128_si256 (_mm256_castsi128_si256(rlo), rhi, 1); + } +#endif + + + template <> + class SIMD + { + __m256i mask; + public: + SIMD (size_t i) + : mask(my_mm256_cmpgt_epi64(_mm256_set1_epi64x(i), + _mm256_set_epi64x(3, 2, 1, 0))) + { ; } + SIMD (__m256i _mask) : mask(_mask) { ; } + SIMD (__m256d _mask) : mask(_mm256_castpd_si256(_mask)) { ; } + __m256i Data() const { return mask; } + static constexpr int Size() { return 4; } + static SIMD GetMaskFromBits (unsigned int i); + }; + + static SIMD masks_from_4bits[16] = { + _mm256_set_epi64x (0,0,0,0), _mm256_set_epi64x (0,0,0,-1), + _mm256_set_epi64x (0,0,-1,0), _mm256_set_epi64x (0,0,-1,-1), + _mm256_set_epi64x (0,-1,0,0), _mm256_set_epi64x (0,-1,0,-1), + _mm256_set_epi64x (0,-1,-1,0), _mm256_set_epi64x (0,-1,-1,-1), + _mm256_set_epi64x (-1,0,0,0), _mm256_set_epi64x (-1,0,0,-1), + _mm256_set_epi64x (-1,0,-1,0), _mm256_set_epi64x (-1,0,-1,-1), + _mm256_set_epi64x (-1,-1,0,0), _mm256_set_epi64x (-1,-1,0,-1), + _mm256_set_epi64x (-1,-1,-1,0), _mm256_set_epi64x (-1,-1,-1,-1) + }; + + NETGEN_INLINE SIMD SIMD :: GetMaskFromBits (unsigned int i) + { + return masks_from_4bits[i & 15]; + } + + template<> + class SIMD + { + __m256i data; + + public: + static constexpr int Size() { return 4; } + SIMD () {} + SIMD (const SIMD &) = default; + SIMD & operator= (const SIMD &) = default; + + SIMD (int64_t val) { data = _mm256_set1_epi64x(val); } + SIMD (int64_t v0, int64_t v1, int64_t v2, int64_t v3) { data = _mm256_set_epi64x(v3,v2,v1,v0); } + // SIMD (SIMD v0, SIMD v1) : SIMD(v0[0], v0[1], v1[0], v1[1]) { ; } + SIMD (__m256i _data) { data = _data; } + + NETGEN_INLINE auto operator[] (int i) const { return ((int64_t*)(&data))[i]; } + NETGEN_INLINE __m256i Data() const { return data; } + NETGEN_INLINE __m256i & Data() { return data; } + + SIMD Lo() const { return _mm256_extractf128_si256(data, 0); } + SIMD Hi() const { return _mm256_extractf128_si256(data, 1); } + static SIMD FirstInt(int n0=0) { return { n0+0, n0+1, n0+2, n0+3 }; } + }; + + + NETGEN_INLINE SIMD operator-(SIMD a) { return _mm256_sub_epi64(_mm256_setzero_si256(), a.Data()); } + +#ifdef __AVX2__ + NETGEN_INLINE SIMD operator+ (SIMD a, SIMD b) { return _mm256_add_epi64(a.Data(),b.Data()); } + NETGEN_INLINE SIMD operator- (SIMD a, SIMD b) { return _mm256_sub_epi64(a.Data(),b.Data()); } +#else + NETGEN_INLINE SIMD operator+ (SIMD a, SIMD b) { + auto lo_sum = _mm256_extractf128_si256(a.Data(), 0) + _mm256_extractf128_si256(b.Data(), 0); + auto hi_sum = _mm256_extractf128_si256(a.Data(), 1) + _mm256_extractf128_si256(b.Data(), 1); + return _mm256_set_m128i(hi_sum,lo_sum); + } + NETGEN_INLINE SIMD operator- (SIMD a, SIMD b) { + auto lo_sub = _mm256_extractf128_si256(a.Data(), 0) - _mm256_extractf128_si256(b.Data(), 0); + auto hi_sub = _mm256_extractf128_si256(a.Data(), 1) - _mm256_extractf128_si256(b.Data(), 1); + return _mm256_set_m128i(hi_sub,lo_sub); + } +#endif + + template<> + class SIMD + { + __m256d data; + + public: + static constexpr int Size() { return 4; } + SIMD () {} + SIMD (const SIMD &) = default; + SIMD & operator= (const SIMD &) = default; + + SIMD (double val) { data = _mm256_set1_pd(val); } + SIMD (int val) { data = _mm256_set1_pd(val); } + SIMD (size_t val) { data = _mm256_set1_pd(val); } + SIMD (double v0, double v1, double v2, double v3) { data = _mm256_set_pd(v3,v2,v1,v0); } + SIMD (SIMD v0, SIMD v1) : SIMD(v0[0], v0[1], v1[0], v1[1]) { ; } + SIMD (double const * p) { data = _mm256_loadu_pd(p); } + SIMD (double const * p, SIMD mask) { data = _mm256_maskload_pd(p, mask.Data()); } + SIMD (__m256d _data) { data = _data; } + + void Store (double * p) { _mm256_storeu_pd(p, data); } + void Store (double * p, SIMD mask) { _mm256_maskstore_pd(p, mask.Data(), data); } + + template>::value, int>::type = 0> + SIMD (const T & func) + { + data = _mm256_set_pd(func(3), func(2), func(1), func(0)); + } + + NETGEN_INLINE double operator[] (int i) const { return ((double*)(&data))[i]; } + NETGEN_INLINE double & operator[] (int i) { return ((double*)(&data))[i]; } + // [[deprecated("don't write to individual elments of SIMD")]] + // NETGEN_INLINE double & operator[] (int i) { return ((double*)(&data))[i]; } + template + double Get() const { return ((double*)(&data))[I]; } + NETGEN_INLINE __m256d Data() const { return data; } + NETGEN_INLINE __m256d & Data() { return data; } + + SIMD Lo() const { return _mm256_extractf128_pd(data, 0); } + SIMD Hi() const { return _mm256_extractf128_pd(data, 1); } + + operator std::tuple () + { return std::tuple((*this)[0], (*this)[1], (*this)[2], (*this)[3]); } + }; + + NETGEN_INLINE auto Unpack (SIMD a, SIMD b) + { + return std::make_tuple(SIMD(_mm256_unpacklo_pd(a.Data(),b.Data())), + SIMD(_mm256_unpackhi_pd(a.Data(),b.Data()))); + } + + NETGEN_INLINE SIMD operator- (SIMD a) { return _mm256_xor_pd(a.Data(), _mm256_set1_pd(-0.0)); } + NETGEN_INLINE SIMD operator+ (SIMD a, SIMD b) { return _mm256_add_pd(a.Data(),b.Data()); } + NETGEN_INLINE SIMD operator- (SIMD a, SIMD b) { return _mm256_sub_pd(a.Data(),b.Data()); } + NETGEN_INLINE SIMD operator* (SIMD a, SIMD b) { return _mm256_mul_pd(a.Data(),b.Data()); } + NETGEN_INLINE SIMD operator/ (SIMD a, SIMD b) { return _mm256_div_pd(a.Data(),b.Data()); } + NETGEN_INLINE SIMD operator* (double a, SIMD b) { return _mm256_set1_pd(a)*b.Data(); } + NETGEN_INLINE SIMD operator* (SIMD b, double a) { return _mm256_set1_pd(a)*b.Data(); } + + NETGEN_INLINE SIMD sqrt (SIMD a) { return _mm256_sqrt_pd(a.Data()); } + NETGEN_INLINE SIMD floor (SIMD a) { return _mm256_floor_pd(a.Data()); } + NETGEN_INLINE SIMD ceil (SIMD a) { return _mm256_ceil_pd(a.Data()); } + NETGEN_INLINE SIMD fabs (SIMD a) { return _mm256_max_pd(a.Data(), -a.Data()); } + + NETGEN_INLINE SIMD operator<= (SIMD a , SIMD b) + { return _mm256_cmp_pd (a.Data(), b.Data(), _CMP_LE_OQ); } + NETGEN_INLINE SIMD operator< (SIMD a , SIMD b) + { return _mm256_cmp_pd (a.Data(), b.Data(), _CMP_LT_OQ); } + NETGEN_INLINE SIMD operator>= (SIMD a , SIMD b) + { return _mm256_cmp_pd (a.Data(), b.Data(), _CMP_GE_OQ); } + NETGEN_INLINE SIMD operator> (SIMD a , SIMD b) + { return _mm256_cmp_pd (a.Data(), b.Data(), _CMP_GT_OQ); } + NETGEN_INLINE SIMD operator== (SIMD a , SIMD b) + { return _mm256_cmp_pd (a.Data(), b.Data(), _CMP_EQ_OQ); } + NETGEN_INLINE SIMD operator!= (SIMD a , SIMD b) + { return _mm256_cmp_pd (a.Data(), b.Data(), _CMP_NEQ_OQ); } + + NETGEN_INLINE SIMD operator<= (SIMD a , SIMD b) + { return _mm256_xor_si256(_mm256_cmpgt_epi64(a.Data(),b.Data()),_mm256_set1_epi32(-1)); } + NETGEN_INLINE SIMD operator< (SIMD a , SIMD b) + { return my_mm256_cmpgt_epi64(b.Data(),a.Data()); } + NETGEN_INLINE SIMD operator>= (SIMD a , SIMD b) + { return _mm256_xor_si256(_mm256_cmpgt_epi64(b.Data(),a.Data()),_mm256_set1_epi32(-1)); } + NETGEN_INLINE SIMD operator> (SIMD a , SIMD b) + { return my_mm256_cmpgt_epi64(a.Data(),b.Data()); } + NETGEN_INLINE SIMD operator== (SIMD a , SIMD b) + { return _mm256_cmpeq_epi64(a.Data(),b.Data()); } + NETGEN_INLINE SIMD operator!= (SIMD a , SIMD b) + { return _mm256_xor_si256(_mm256_cmpeq_epi64(a.Data(),b.Data()),_mm256_set1_epi32(-1)); } + +#ifdef __AVX2__ + NETGEN_INLINE SIMD operator&& (SIMD a, SIMD b) + { return _mm256_and_si256 (a.Data(), b.Data()); } + NETGEN_INLINE SIMD operator|| (SIMD a, SIMD b) + { return _mm256_or_si256 (a.Data(), b.Data()); } + NETGEN_INLINE SIMD operator! (SIMD a) + { return _mm256_xor_si256 (a.Data(), _mm256_cmpeq_epi64(a.Data(),a.Data())); } +#else //AVX2 is a superset of AVX. Without it, it is necessary to reinterpret the types + NETGEN_INLINE SIMD operator&& (SIMD a, SIMD b) + { return _mm256_castpd_si256(_mm256_and_pd (_mm256_castsi256_pd(a.Data()),_mm256_castsi256_pd( b.Data()))); } + NETGEN_INLINE SIMD operator|| (SIMD a, SIMD b) + { return _mm256_castpd_si256(_mm256_or_pd (_mm256_castsi256_pd(a.Data()), _mm256_castsi256_pd(b.Data()))); } + NETGEN_INLINE SIMD operator! (SIMD a) + { return _mm256_castpd_si256(_mm256_xor_pd (_mm256_castsi256_pd(a.Data()),_mm256_castsi256_pd( _mm256_cmpeq_epi64(a.Data(),a.Data())))); } +#endif + NETGEN_INLINE SIMD If (SIMD a, SIMD b, SIMD c) + { return _mm256_blendv_pd(c.Data(), b.Data(), _mm256_castsi256_pd(a.Data())); } + + NETGEN_INLINE SIMD IfPos (SIMD a, SIMD b, SIMD c) + { + auto cp = _mm256_cmp_pd (a.Data(), _mm256_setzero_pd(), _CMP_GT_OS); + return _mm256_blendv_pd(c.Data(), b.Data(), cp); + } + + NETGEN_INLINE SIMD IfZero (SIMD a, SIMD b, SIMD c) + { + auto cp = _mm256_cmp_pd (a.Data(), _mm256_setzero_pd(), _CMP_EQ_OS); + return _mm256_blendv_pd(c.Data(), b.Data(), cp); + } + + NETGEN_INLINE double HSum (SIMD sd) + { + // __m128d hv = _mm_add_pd (_mm256_extractf128_pd(sd.Data(),0), _mm256_extractf128_pd(sd.Data(),1)); + __m128d hv = (sd.Lo()+sd.Hi()).Data(); + return _mm_cvtsd_f64 (_mm_hadd_pd (hv, hv)); + } + + NETGEN_INLINE auto HSum (SIMD sd1, SIMD sd2) + { + __m256d hv = _mm256_hadd_pd(sd1.Data(), sd2.Data()); + __m128d hv2 = _mm_add_pd (_mm256_extractf128_pd(hv,0), _mm256_extractf128_pd(hv,1)); + return SIMD(_mm_cvtsd_f64 (hv2), _mm_cvtsd_f64(_mm_shuffle_pd (hv2, hv2, 3))); + } + + NETGEN_INLINE auto HSum (SIMD v1, SIMD v2, SIMD v3, SIMD v4) + { + __m256d hsum1 = _mm256_hadd_pd (v1.Data(), v2.Data()); + __m256d hsum2 = _mm256_hadd_pd (v3.Data(), v4.Data()); + SIMD hsum = _mm256_add_pd (_mm256_permute2f128_pd (hsum1, hsum2, 1+2*16), + _mm256_blend_pd (hsum1, hsum2, 12)); + return hsum; + // return make_tuple(hsum[0], hsum[1], hsum[2], hsum[3]); + } + + + NETGEN_INLINE SIMD If (SIMD a, SIMD b, SIMD c) + { return _mm256_castpd_si256(_mm256_blendv_pd(_mm256_castsi256_pd(c.Data()), _mm256_castsi256_pd(b.Data()), + _mm256_castsi256_pd(a.Data()))); } + +} + +#endif // NETGEN_CORE_SIMD_AVX_HPP + diff --git a/libsrc/core/simd_avx512.hpp b/libsrc/core/simd_avx512.hpp new file mode 100644 index 00000000..4c461371 --- /dev/null +++ b/libsrc/core/simd_avx512.hpp @@ -0,0 +1,239 @@ +#ifndef NETGEN_CORE_SIMD_AVX512_HPP +#define NETGEN_CORE_SIMD_AVX512_HPP + +/**************************************************************************/ +/* File: simd_avx512.hpp */ +/* Author: Joachim Schoeberl, Matthias Hochsteger */ +/* Date: 25. Mar. 16 */ +/**************************************************************************/ + +#include + +namespace ngcore +{ + + template <> + class SIMD + { + __mmask8 mask; + public: + SIMD (size_t i) + : mask(_mm512_cmpgt_epi64_mask(_mm512_set1_epi64(i), + _mm512_set_epi64(7, 6, 5, 4, 3, 2, 1, 0))) + { ; } + SIMD (int i) + : mask(_mm512_cmpgt_epi64_mask(_mm512_set1_epi64(i), + _mm512_set_epi64(7, 6, 5, 4, 3, 2, 1, 0))) + { ; } + SIMD (int64_t i) + : mask(_mm512_cmpgt_epi64_mask(_mm512_set1_epi64(i), + _mm512_set_epi64(7, 6, 5, 4, 3, 2, 1, 0))) + { ; } + SIMD (__mmask8 _mask) : mask(_mask) { ; } + __mmask8 Data() const { return mask; } + static constexpr int Size() { return 8; } + static NETGEN_INLINE SIMD GetMaskFromBits (unsigned int i) + { + return SIMD(__mmask8(i)); + } + }; + + template<> + class SIMD + { + __m512i data; + + public: + static constexpr int Size() { return 8; } + SIMD () {} + SIMD (const SIMD &) = default; + SIMD & operator= (const SIMD &) = default; + + SIMD (int64_t val) { data = _mm512_set1_epi64(val); } + SIMD (int64_t v0, int64_t v1, int64_t v2, int64_t v3, int64_t v4, int64_t v5, int64_t v6, int64_t v7) { data = _mm512_set_epi64(v7,v6,v5,v4,v3,v2,v1,v0); } + SIMD (__m512i _data) { data = _data; } + + template>::value, int>::type = 0> + SIMD (const T & func) + { + data = _mm512_set_epi64(func(7), func(6), func(5), func(4), func(3), func(2), func(1), func(0)); + } + + + NETGEN_INLINE auto operator[] (int i) const { return ((int64_t*)(&data))[i]; } + NETGEN_INLINE __m512i Data() const { return data; } + NETGEN_INLINE __m512i & Data() { return data; } + static SIMD FirstInt() { return { 0, 1, 2, 3, 4, 5, 6, 7 }; } + }; + + NETGEN_INLINE SIMD operator-(SIMD a) { return _mm512_sub_epi64(_mm512_setzero_si512(), a.Data()); } + + NETGEN_INLINE SIMD operator+ (SIMD a, SIMD b) { return _mm512_add_epi64(a.Data(),b.Data()); } + NETGEN_INLINE SIMD operator- (SIMD a, SIMD b) { return _mm512_sub_epi64(a.Data(),b.Data()); } + + NETGEN_INLINE SIMD If (SIMD a, SIMD b, SIMD c) + { return _mm512_mask_blend_epi64(a.Data(), c.Data(), b.Data()); } + + + template<> + class SIMD : public AlignedAlloc> + { + __m512d data; + public: + static constexpr int Size() { return 8; } + SIMD () {} + SIMD (const SIMD &) = default; + SIMD & operator= (const SIMD &) = default; + + SIMD (double val) { data = _mm512_set1_pd(val); } + SIMD (int val) { data = _mm512_set1_pd(val); } + SIMD (size_t val) { data = _mm512_set1_pd(val); } + SIMD (double const * p) { data = _mm512_loadu_pd(p); } + SIMD (double const * p, SIMD mask) + { data = _mm512_mask_loadu_pd(_mm512_setzero_pd(), mask.Data(), p); } + SIMD (__m512d _data) { data = _data; } + + template>::value, int>::type = 0> + SIMD (const T & func) + { + data = _mm512_set_pd(func(7), func(6), func(5), func(4), func(3), func(2), func(1), func(0)); + } + + void Store (double * p) { _mm512_storeu_pd(p, data); } + void Store (double * p, SIMD mask) { _mm512_mask_storeu_pd(p, mask.Data(), data); } + + template + void SIMD_function (const Function & func, std::true_type) + { + data = (__m512){ func(7), func(6), func(5), func(4), + func(3), func(2), func(1), func(0) }; + } + + // not a function + void SIMD_function (double const * p, std::false_type) + { + data = _mm512_loadu_pd(p); + } + + void SIMD_function (double val, std::false_type) + { + data = _mm512_set1_pd(val); + } + + void SIMD_function (__m512d _data, std::false_type) + { + data = _data; + } + + NETGEN_INLINE double operator[] (int i) const { return ((double*)(&data))[i]; } + NETGEN_INLINE __m512d Data() const { return data; } + NETGEN_INLINE __m512d & Data() { return data; } + + }; + + NETGEN_INLINE SIMD operator- (SIMD a) { return -a.Data(); } + NETGEN_INLINE SIMD operator+ (SIMD a, SIMD b) { return _mm512_add_pd(a.Data(),b.Data()); } + NETGEN_INLINE SIMD operator- (SIMD a, SIMD b) { return _mm512_sub_pd(a.Data(),b.Data()); } + NETGEN_INLINE SIMD operator* (SIMD a, SIMD b) { return _mm512_mul_pd(a.Data(),b.Data()); } + NETGEN_INLINE SIMD operator/ (SIMD a, SIMD b) { return _mm512_div_pd(a.Data(),b.Data()); } + NETGEN_INLINE SIMD operator* (double a, SIMD b) { return _mm512_set1_pd(a)*b.Data(); } + NETGEN_INLINE SIMD operator* (SIMD b, double a) { return _mm512_set1_pd(a)*b.Data(); } + + NETGEN_INLINE SIMD sqrt (SIMD a) { return _mm512_sqrt_pd(a.Data()); } + NETGEN_INLINE SIMD floor (SIMD a) { return _mm512_floor_pd(a.Data()); } + NETGEN_INLINE SIMD ceil (SIMD a) { return _mm512_ceil_pd(a.Data()); } + NETGEN_INLINE SIMD fabs (SIMD a) { return _mm512_max_pd(a.Data(), -a.Data()); } + + NETGEN_INLINE SIMD operator<= (SIMD a , SIMD b) + { return _mm512_cmp_pd_mask (a.Data(), b.Data(), _CMP_LE_OQ); } + NETGEN_INLINE SIMD operator< (SIMD a , SIMD b) + { return _mm512_cmp_pd_mask (a.Data(), b.Data(), _CMP_LT_OQ); } + NETGEN_INLINE SIMD operator>= (SIMD a , SIMD b) + { return _mm512_cmp_pd_mask (a.Data(), b.Data(), _CMP_GE_OQ); } + NETGEN_INLINE SIMD operator> (SIMD a , SIMD b) + { return _mm512_cmp_pd_mask (a.Data(), b.Data(), _CMP_GT_OQ); } + NETGEN_INLINE SIMD operator== (SIMD a , SIMD b) + { return _mm512_cmp_pd_mask (a.Data(), b.Data(), _CMP_EQ_OQ); } + NETGEN_INLINE SIMD operator!= (SIMD a , SIMD b) + { return _mm512_cmp_pd_mask (a.Data(), b.Data(), _CMP_NEQ_OQ); } + + NETGEN_INLINE SIMD operator<= (SIMD a , SIMD b) + { return _mm512_cmp_epi64_mask (a.Data(), b.Data(), _MM_CMPINT_LE); } + NETGEN_INLINE SIMD operator< (SIMD a , SIMD b) + { return _mm512_cmp_epi64_mask (a.Data(), b.Data(), _MM_CMPINT_LT); } + NETGEN_INLINE SIMD operator>= (SIMD a , SIMD b) + { return _mm512_cmp_epi64_mask (a.Data(), b.Data(), _MM_CMPINT_NLT); } + NETGEN_INLINE SIMD operator> (SIMD a , SIMD b) + { return _mm512_cmp_epi64_mask (a.Data(), b.Data(), _MM_CMPINT_NLE); } + NETGEN_INLINE SIMD operator== (SIMD a , SIMD b) + { return _mm512_cmp_epi64_mask (a.Data(), b.Data(), _MM_CMPINT_EQ); } + NETGEN_INLINE SIMD operator!= (SIMD a , SIMD b) + { return _mm512_cmp_epi64_mask (a.Data(), b.Data(), _MM_CMPINT_NE); } + + NETGEN_INLINE SIMD operator&& (SIMD a, SIMD b) + { return (__mmask8)(a.Data() & b.Data()); } + NETGEN_INLINE SIMD operator|| (SIMD a, SIMD b) + { return (__mmask8)(a.Data() | b.Data()); } + NETGEN_INLINE SIMD operator! (SIMD a) + { return (__mmask8)(~a.Data()); } + + NETGEN_INLINE SIMD If (SIMD a, SIMD b, SIMD c) + { return _mm512_mask_blend_pd(a.Data(), c.Data(), b.Data()); } + + NETGEN_INLINE SIMD IfPos (SIMD a, SIMD b, SIMD c) + { + auto k = _mm512_cmp_pd_mask(a.Data(),_mm512_setzero_pd(), _CMP_GT_OS); + return _mm512_mask_blend_pd(k,c.Data(),b.Data()); + } + NETGEN_INLINE SIMD IfZero (SIMD a, SIMD b, SIMD c) + { + auto k = _mm512_cmp_pd_mask(a.Data(),_mm512_setzero_pd(), _CMP_EQ_OS); + return _mm512_mask_blend_pd(k,c.Data(),b.Data()); + } + + + NETGEN_INLINE auto Unpack (SIMD a, SIMD b) + { + return std::make_tuple(SIMD(_mm512_unpacklo_pd(a.Data(),b.Data())), + SIMD(_mm512_unpackhi_pd(a.Data(),b.Data()))); + } + + + NETGEN_INLINE double HSum (SIMD sd) + { + SIMD low = _mm512_extractf64x4_pd(sd.Data(),0); + SIMD high = _mm512_extractf64x4_pd(sd.Data(),1); + return HSum(low)+HSum(high); + } + + NETGEN_INLINE auto HSum (SIMD sd1, SIMD sd2) + { + return SIMD(HSum(sd1), HSum(sd2)); + } + + NETGEN_INLINE SIMD HSum (SIMD v1, SIMD v2, SIMD v3, SIMD v4) + { + SIMD lo,hi; + tie(lo,hi) = Unpack(v1, v2); + SIMD sum01 = lo+hi; + tie(lo,hi) = Unpack(v3, v4); + SIMD sum23 = lo+hi; + // sum01 b a b a b a b a + // sum23 d c d c d c d c + // __m512 perm = _mm512_permutex2var_pd (sum01.Data(), _mm512_set_epi64(1,2,3,4,5,6,7,8), sum23.Data()); + __m256d ab = _mm512_extractf64x4_pd(sum01.Data(),0) + _mm512_extractf64x4_pd(sum01.Data(),1); + __m256d cd = _mm512_extractf64x4_pd(sum23.Data(),0) + _mm512_extractf64x4_pd(sum23.Data(),1); + return _mm256_add_pd (_mm256_permute2f128_pd (ab, cd, 1+2*16), _mm256_blend_pd (ab, cd, 12)); + } + + NETGEN_INLINE SIMD FMA (SIMD a, SIMD b, SIMD c) + { + return _mm512_fmadd_pd (a.Data(), b.Data(), c.Data()); + } + NETGEN_INLINE SIMD FMA (const double & a, SIMD b, SIMD c) + { + return _mm512_fmadd_pd (_mm512_set1_pd(a), b.Data(), c.Data()); + } +} + +#endif // NETGEN_CORE_SIMD_AVX512_HPP diff --git a/libsrc/core/simd_generic.hpp b/libsrc/core/simd_generic.hpp new file mode 100644 index 00000000..8cebe30b --- /dev/null +++ b/libsrc/core/simd_generic.hpp @@ -0,0 +1,597 @@ +#ifndef NETGEN_CORE_SIMD_GENERIC_HPP +#define NETGEN_CORE_SIMD_GENERIC_HPP + +/**************************************************************************/ +/* File: simd_base.hpp */ +/* Author: Joachim Schoeberl, Matthias Hochsteger */ +/* Date: 25. Mar. 16 */ +/**************************************************************************/ + +#include +#include +#include + +#include "array.hpp" + +namespace ngcore +{ + using namespace ngcore; + + constexpr int GetDefaultSIMDSize() { +#if defined __AVX512F__ + return 8; +#elif defined __AVX__ + return 4; +#elif (defined(_M_AMD64) || defined(_M_X64) || defined(__SSE__)) + return 2; +#else + return 1; +#endif + } + + + template class SIMD; + + class mask64; + + //////////////////////////////////////////////////////////////////////////// + // mask + + template <> + class SIMD + { + int64_t mask; + public: + SIMD (size_t i) + : mask(i > 0 ? -1 : 0) { ; } + bool Data() const { return mask; } + static constexpr int Size() { return 1; } + auto operator[] (int /* i */) const { return mask; } + }; + + + template + class SIMD + { + static constexpr int N1 = std::min(GetDefaultSIMDSize(), N/2); + static constexpr int N2 = N-N1; + + SIMD lo; + SIMD hi; + public: + + SIMD (int i) : lo(i), hi(i-N1) { ; } + SIMD (SIMD lo_, SIMD hi_) : lo(lo_), hi(hi_) { ; } + SIMD Lo() const { return lo; } + SIMD Hi() const { return hi; } + static constexpr int Size() { return N; } + }; + + template + NETGEN_INLINE SIMD operator&& (SIMD a, SIMD b) + { + if constexpr(N==1) return a.Data() && b.Data(); + else return { a.Lo() && b.Lo(), a.Hi() && b.Hi() }; + } + + + //////////////////////////////////////////////////////////////////////////// + // int64 + + template<> + class SIMD + { + int64_t data; + + public: + static constexpr int Size() { return 1; } + SIMD () {} + SIMD (const SIMD &) = default; + SIMD & operator= (const SIMD &) = default; + SIMD (int64_t val) { data = val; } + + int64_t operator[] (int i) const { return ((int64_t*)(&data))[i]; } + auto Data() const { return data; } + static SIMD FirstInt(int64_t n0=0) { return {n0}; } + }; + + template + class SIMD + { + static constexpr int N1 = std::min(GetDefaultSIMDSize(), N/2); + static constexpr int N2 = N-N1; + + SIMD lo; + SIMD high; + + public: + static constexpr int Size() { return N; } + + SIMD () {} + SIMD (const SIMD &) = default; + SIMD & operator= (const SIMD &) = default; + + SIMD (int64_t val) : lo{val}, high{val} { ; } + SIMD (SIMD lo_, SIMD high_) : lo(lo_), high(high_) { ; } + + template>::value, int>::type = 0> + SIMD (const T & func) + { + for(auto i : IntRange(N1)) + lo[i] = func(i); + for(auto i : IntRange(N2)) + high[i] = func(N1+i); + } + + auto Lo() const { return lo; } + auto Hi() const { return high; } + + int64_t operator[] (int i) const { return ((int64_t*)(&lo))[i]; } + + /* + operator tuple () + { return tuple((*this)[0], (*this)[1], (*this)[2], (*this)[3]); } + */ + + /* + static SIMD FirstInt() { return { 0, 1, 2, 3 }; } + */ + static SIMD FirstInt(int64_t n0=0) { return {SIMD::FirstInt(n0), SIMD::FirstInt(n0+N1)}; } + }; + + + //////////////////////////////////////////////////////////////////////////// + // double + + template<> + class SIMD + { + double data; + + public: + static constexpr int Size() { return 1; } + SIMD () {} + SIMD (const SIMD &) = default; + SIMD & operator= (const SIMD &) = default; + SIMD (double val) { data = val; } + SIMD (int val) { data = val; } + SIMD (size_t val) { data = val; } + SIMD (double const * p) { data = *p; } + SIMD (double const * p, SIMD mask) { data = mask.Data() ? *p : 0.0; } + + template >::value,int>::type = 0> + SIMD (const T & func) + { + data = func(0); + } + + template >::value,int>::type = 0> + SIMD & operator= (const T & func) + { + data = func(0); + return *this; + } + + void Store (double * p) { *p = data; } + void Store (double * p, SIMD mask) { if (mask.Data()) *p = data; } + + double operator[] (int i) const { return ((double*)(&data))[i]; } + double Data() const { return data; } + }; + + template + class SIMD + { + static constexpr int N1 = std::min(GetDefaultSIMDSize(), N/2); + static constexpr int N2 = N-N1; + + SIMD lo; + SIMD high; + + public: + static constexpr int Size() { return N; } + SIMD () {} + SIMD (const SIMD &) = default; + SIMD (SIMD lo_, SIMD hi_) : lo(lo_), high(hi_) { ; } + + template> + SIMD (double v0, double v1, double v2, double v3) + { + if constexpr(N1==1) + { + lo = v0; + high = {v1,v2,v3}; + } + if constexpr(N1==2) + { + lo = {v0,v1}; + high = {v2,v3}; + + } + } + + template >::value,int>::type = 0> + SIMD (const T & func) + { + for(auto i : IntRange(N1)) + lo[i] = func(i); + for(auto i : IntRange(N2)) + high[i] = func(N1+i); + } + + template >::value,int>::type = 0> + SIMD & operator= (const T & func) + { + for(auto i : IntRange(N1)) + lo[i] = func(i); + for(auto i : IntRange(N2)) + high[i] = func(N1+i); + return *this; + } + + + SIMD & operator= (const SIMD &) = default; + + SIMD (double val) : lo{val}, high{val} { ; } + SIMD (int val) : lo{val}, high{val} { ; } + SIMD (size_t val) : lo{val}, high{val} { ; } + + SIMD (double const * p) : lo{p}, high{p+N1} { ; } + SIMD (double const * p, SIMD mask) + : lo{p, mask.Lo()}, high{p+N1, mask.Hi()} + { } + + void Store (double * p) { lo.Store(p); high.Store(p+N1); } + void Store (double * p, SIMD mask) + { + lo.Store(p, mask.Lo()); + high.Store(p+N1, mask.Hi()); + } + + auto Lo() const { return lo; } + auto Hi() const { return high; } + + double operator[] (int i) const { return ((double*)(&lo))[i]; } + + template> + operator std::tuple () + { return std::tuple((*this)[0], (*this)[1]); } + + template> + operator std::tuple () + { return std::tuple((*this)[0], (*this)[1], (*this)[2], (*this)[3]); } + + }; + + + // Generic operators for any arithmetic type/simd width + template + NETGEN_INLINE SIMD operator+ (SIMD a, SIMD b) { + if constexpr(N==1) return a.Data()+b.Data(); + else return { a.Lo()+b.Lo(), a.Hi()+b.Hi() }; + } + + template + NETGEN_INLINE SIMD operator- (SIMD a, SIMD b) { + if constexpr(N==1) return a.Data()-b.Data(); + else return { a.Lo()-b.Lo(), a.Hi()+b.Hi() }; + } + template + NETGEN_INLINE SIMD operator- (SIMD a) { + if constexpr(N==1) return -a.Data(); + else return { -a.Lo(), -a.Hi() }; + } + + template + NETGEN_INLINE SIMD operator* (SIMD a, SIMD b) { + if constexpr(N==1) return a.Data()*b.Data(); + else return { a.Lo()*b.Lo(), a.Hi()+b.Hi() }; + } + + template + NETGEN_INLINE SIMD operator/ (SIMD a, SIMD b) { + if constexpr(N==1) return a.Data()/b.Data(); + else return { a.Lo()/b.Lo(), a.Hi()+b.Hi() }; + } + + template + NETGEN_INLINE SIMD operator< (SIMD & a, SIMD b) + { + if constexpr(N==1) return a.Data() < b.Data(); + else return { a.Lo() + NETGEN_INLINE SIMD operator<= (SIMD & a, SIMD b) + { + if constexpr(N==1) return a.Data() <= b.Data(); + else return { a.Lo()<=b.Lo(), a.Hi()<=b.Hi() }; + } + + template + NETGEN_INLINE SIMD operator> (SIMD & a, SIMD b) + { + if constexpr(N==1) return a.Data() > b.Data(); + else return { a.Lo()>b.Lo(), a.Hi()>b.Hi() }; + } + + template + NETGEN_INLINE SIMD operator>= (SIMD & a, SIMD b) + { + if constexpr(N==1) return a.Data() >= b.Data(); + else return { a.Lo()>=b.Lo(), a.Hi()>=b.Hi() }; + } + + template + NETGEN_INLINE SIMD operator== (SIMD & a, SIMD b) + { + if constexpr(N==1) return a.Data() == b.Data(); + else return { a.Lo()==b.Lo(), a.Hi()==b.Hi() }; + } + + template + NETGEN_INLINE SIMD operator!= (SIMD & a, SIMD b) + { + if constexpr(N==1) return a.Data() != b.Data(); + else return { a.Lo()!=b.Lo(), a.Hi()!=b.Hi() }; + } + + // int64_t operators with scalar operand (implement overloads to allow implicit casts for second operand) + template + NETGEN_INLINE SIMD operator+ (SIMD a, int64_t b) { return a+SIMD(b); } + template + NETGEN_INLINE SIMD operator+ (int64_t a, SIMD b) { return SIMD(a)+b; } + template + NETGEN_INLINE SIMD operator- (int64_t a, SIMD b) { return SIMD(a)-b; } + template + NETGEN_INLINE SIMD operator- (SIMD a, int64_t b) { return a-SIMD(b); } + template + NETGEN_INLINE SIMD operator* (int64_t a, SIMD b) { return SIMD(a)*b; } + template + NETGEN_INLINE SIMD operator* (SIMD b, int64_t a) { return SIMD(a)*b; } + template + NETGEN_INLINE SIMD operator/ (SIMD a, int64_t b) { return a/SIMD(b); } + template + NETGEN_INLINE SIMD operator/ (int64_t a, SIMD b) { return SIMD(a)/b; } + template + NETGEN_INLINE SIMD & operator+= (SIMD & a, SIMD b) { a=a+b; return a; } + template + NETGEN_INLINE SIMD & operator+= (SIMD & a, int64_t b) { a+=SIMD(b); return a; } + template + NETGEN_INLINE SIMD & operator-= (SIMD & a, SIMD b) { a = a-b; return a; } + template + NETGEN_INLINE SIMD & operator-= (SIMD & a, int64_t b) { a-=SIMD(b); return a; } + template + NETGEN_INLINE SIMD & operator*= (SIMD & a, SIMD b) { a=a*b; return a; } + template + NETGEN_INLINE SIMD & operator*= (SIMD & a, int64_t b) { a*=SIMD(b); return a; } + template + NETGEN_INLINE SIMD & operator/= (SIMD & a, SIMD b) { a = a/b; return a; } + + // double operators with scalar operand (implement overloads to allow implicit casts for second operand) + template + NETGEN_INLINE SIMD operator+ (SIMD a, double b) { return a+SIMD(b); } + template + NETGEN_INLINE SIMD operator+ (double a, SIMD b) { return SIMD(a)+b; } + template + NETGEN_INLINE SIMD operator- (double a, SIMD b) { return SIMD(a)-b; } + template + NETGEN_INLINE SIMD operator- (SIMD a, double b) { return a-SIMD(b); } + template + NETGEN_INLINE SIMD operator* (double a, SIMD b) { return SIMD(a)*b; } + template + NETGEN_INLINE SIMD operator* (SIMD b, double a) { return SIMD(a)*b; } + template + NETGEN_INLINE SIMD operator/ (SIMD a, double b) { return a/SIMD(b); } + template + NETGEN_INLINE SIMD operator/ (double a, SIMD b) { return SIMD(a)/b; } + template + NETGEN_INLINE SIMD & operator+= (SIMD & a, SIMD b) { a=a+b; return a; } + template + NETGEN_INLINE SIMD & operator+= (SIMD & a, double b) { a+=SIMD(b); return a; } + template + NETGEN_INLINE SIMD & operator-= (SIMD & a, SIMD b) { a = a-b; return a; } + template + NETGEN_INLINE SIMD & operator-= (SIMD & a, double b) { a-=SIMD(b); return a; } + template + NETGEN_INLINE SIMD & operator*= (SIMD & a, SIMD b) { a=a*b; return a; } + template + NETGEN_INLINE SIMD & operator*= (SIMD & a, double b) { a*=SIMD(b); return a; } + template + NETGEN_INLINE SIMD & operator/= (SIMD & a, SIMD b) { a = a/b; return a; } + + // double functions + + template + NETGEN_INLINE SIMD L2Norm2 (SIMD a) { return a*a; } + template + NETGEN_INLINE SIMD Trans (SIMD a) { return a; } + + template + NETGEN_INLINE double HSum (SIMD a) + { + if constexpr(N==1) + return a.Data(); + else + return HSum(a.Lo()) + HSum(a.Hi()); + } + + NETGEN_INLINE double IfPos (double a, double b, double c) { return a>0 ? b : c; } + NETGEN_INLINE double IfZero (double a, double b, double c) { return a==0. ? b : c; } + + template + NETGEN_INLINE SIMD IfPos (SIMD a, SIMD b, SIMD c) + { + if constexpr(N==1) return a.Data()>0.0 ? b : c; + else return { IfPos(a.Lo(), b.Lo(), c.Lo()), IfPos(a.Hi(), b.Hi(), c.Hi())}; + + } + + template + NETGEN_INLINE SIMD IfZero (SIMD a, SIMD b, SIMD c) + { + if constexpr(N==1) return a.Data()==0.0 ? b : c; + else return { IfZero(a.Lo(), b.Lo(), c.Lo()), IfZero(a.Hi(), b.Hi(), c.Hi())}; + + } + + template + NETGEN_INLINE SIMD If (SIMD a, SIMD b, SIMD c) + { + if constexpr(N==1) return a.Data() ? b : c; + else return { If(a.Lo(), b.Lo(), c.Lo()), If(a.Hi(), b.Hi(), c.Hi())}; + + } + + template + // a*b+c + NETGEN_INLINE auto FMA(T1 a, T2 b, T3 c) + { + return a*b+c; + } + + // update form of fma + template + void FMAasm (SIMD a, SIMD b, SIMD & sum) + { + sum = FMA(a,b,sum); + } + + template + T get(SIMD a) { return a[i]; } + + template + NETGEN_INLINE void Iterate2 (FUNC f) + { + if constexpr (NUM > 1) Iterate2 (f); + if constexpr (NUM >= 1) f(std::integral_constant()); + } + + + template + ostream & operator<< (ostream & ost, SIMD simd) + { + /* + ost << simd[0]; + for (int i = 1; i < simd.Size(); i++) + ost << " " << simd[i]; + */ + Iterate2 ([&] (auto I) { + if (I.value != 0) ost << " "; + ost << get(simd); + }); + return ost; + } + + using std::exp; + template + NETGEN_INLINE ngcore::SIMD exp (ngcore::SIMD a) { + return ngcore::SIMD([a](int i)->double { return exp(a[i]); } ); + } + + using std::log; + template + NETGEN_INLINE ngcore::SIMD log (ngcore::SIMD a) { + return ngcore::SIMD([a](int i)->double { return log(a[i]); } ); + } + + using std::pow; + template + NETGEN_INLINE ngcore::SIMD pow (ngcore::SIMD a, double x) { + return ngcore::SIMD([a,x](int i)->double { return pow(a[i],x); } ); + } + + template + NETGEN_INLINE ngcore::SIMD pow (ngcore::SIMD a, ngcore::SIMD b) { + return ngcore::SIMD([a,b](int i)->double { return pow(a[i],b[i]); } ); + } + + using std::sin; + template + NETGEN_INLINE ngcore::SIMD sin (ngcore::SIMD a) { + return ngcore::SIMD([a](int i)->double { return sin(a[i]); } ); + } + + using std::cos; + template + NETGEN_INLINE ngcore::SIMD cos (ngcore::SIMD a) { + return ngcore::SIMD([a](int i)->double { return cos(a[i]); } ); + } + + using std::tan; + template + NETGEN_INLINE ngcore::SIMD tan (ngcore::SIMD a) { + return ngcore::SIMD([a](int i)->double { return tan(a[i]); } ); + } + + using std::atan; + template + NETGEN_INLINE ngcore::SIMD atan (ngcore::SIMD a) { + return ngcore::SIMD([a](int i)->double { return atan(a[i]); } ); + } + + using std::atan2; + template + NETGEN_INLINE ngcore::SIMD atan2 (ngcore::SIMD y, ngcore::SIMD x) { + return ngcore::SIMD([y,x](int i)->double { return atan2(y[i], x[i]); } ); + } + + using std::acos; + template + NETGEN_INLINE ngcore::SIMD acos (ngcore::SIMD a) { + return ngcore::SIMD([a](int i)->double { return acos(a[i]); } ); + } + + using std::asin; + template + NETGEN_INLINE ngcore::SIMD asin (ngcore::SIMD a) { + return ngcore::SIMD([a](int i)->double { return asin(a[i]); } ); + } + + using std::sinh; + template + NETGEN_INLINE ngcore::SIMD sinh (ngcore::SIMD a) { + return ngcore::SIMD([a](int i)->double { return sinh(a[i]); } ); + } + + using std::cosh; + template + NETGEN_INLINE ngcore::SIMD cosh (ngcore::SIMD a) { + return ngcore::SIMD([a](int i)->double { return cosh(a[i]); } ); + } + + template + class AlignedAlloc { ; }; + + template + using MultiSIMD = SIMD; + + template + NETGEN_INLINE auto Unpack (SIMD a, SIMD b) + { + if constexpr(N==1) + { + return std::make_tuple(SIMD{a.Data()}, SIMD{b.Data()} ); + } + else + { + auto [a1,b1] = Unpack(a.Lo(), b.Lo()); + auto [a2,b2] = Unpack(a.Hi(), b.Hi()); + return std::make_tuple(SIMD{ a1, a2 }, + SIMD{ b1, b2 }); + } + } + + + +} + +namespace std +{ + // structured binding support + template + struct tuple_size> : std::integral_constant {}; + template struct tuple_element> { using type = T; }; +} + +#endif // NETGEN_CORE_SIMD_GENERIC_HPP diff --git a/libsrc/core/simd_sse.hpp b/libsrc/core/simd_sse.hpp new file mode 100644 index 00000000..6ea3f021 --- /dev/null +++ b/libsrc/core/simd_sse.hpp @@ -0,0 +1,260 @@ +#ifndef NETGEN_CORE_SIMD_SSE_HPP +#define NETGEN_CORE_SIMD_SSE_HPP + +/**************************************************************************/ +/* File: simd_sse.hpp */ +/* Author: Joachim Schoeberl, Matthias Hochsteger */ +/* Date: 25. Mar. 16 */ +/**************************************************************************/ + +#include + +namespace ngcore +{ + + template <> + class SIMD + { + __m128i mask; + public: + SIMD (int i) + : mask(_mm_cmpgt_epi32(_mm_set1_epi32(i), + _mm_set_epi32(1, 1, 0, 0))) + { ; } + SIMD (__m128i _mask) : mask(_mask) { ; } + __m128i Data() const { return mask; } + static constexpr int Size() { return 2; } + static NETGEN_INLINE SIMD GetMaskFromBits (unsigned int i); + }; + + static SIMD masks_from_2bits[4] = { + _mm_set_epi32 (0,0,0,0), _mm_set_epi32 (0,0,-1,0), + _mm_set_epi32 (-1,0,0,0), _mm_set_epi32 (-1,0,-1,0), + }; + + NETGEN_INLINE SIMD SIMD :: GetMaskFromBits (unsigned int i) + { + return masks_from_2bits[i & 3]; + } + + + template<> + class SIMD + { + __m128i data; + + public: + static constexpr int Size() { return 2; } + SIMD () {} + SIMD (const SIMD &) = default; + SIMD (int64_t v0, int64_t v1) { data = _mm_set_epi64x(v1,v0); } + + SIMD & operator= (const SIMD &) = default; + + SIMD (int64_t val) { data = _mm_set1_epi64x(val); } + SIMD (__m128i _data) { data = _data; } + + template>::value, int>::type = 0> + SIMD (const T & func) + { + data = _mm_set_epi64(func(1), func(0)); + } + + NETGEN_INLINE auto operator[] (int i) const { return ((int64_t*)(&data))[i]; } + NETGEN_INLINE __m128i Data() const { return data; } + NETGEN_INLINE __m128i & Data() { return data; } + static SIMD FirstInt(int n0=0) { return { n0, n0+1 }; } + }; + + + +NETGEN_INLINE SIMD operator-(SIMD a) { return _mm_sub_epi64(_mm_setzero_si128(), a.Data()); } +NETGEN_INLINE SIMD operator+ (SIMD a, SIMD b) { return _mm_add_epi64(a.Data(),b.Data()); } +NETGEN_INLINE SIMD operator- (SIMD a, SIMD b) { return _mm_sub_epi64(a.Data(),b.Data()); } + + + template<> + class alignas(16) SIMD : public AlignedAlloc> + { + __m128d data; + + public: + static constexpr int Size() { return 2; } + SIMD () {} + SIMD (const SIMD &) = default; + SIMD (double v0, double v1) { data = _mm_set_pd(v1,v0); } + + SIMD & operator= (const SIMD &) = default; + + SIMD (double val) { data = _mm_set1_pd(val); } + SIMD (int val) { data = _mm_set1_pd(val); } + SIMD (size_t val) { data = _mm_set1_pd(val); } + + SIMD (double const * p) { data = _mm_loadu_pd(p); } + SIMD (double const * p, SIMD mask) + { +#ifdef __AVX__ + data = _mm_maskload_pd(p, mask.Data()); +#else + // this versions segfaults if p points to the last allowed element + // happened on Mac with the new SparseCholesky-factorization + // data = _mm_and_pd(_mm_castsi128_pd(mask.Data()), _mm_loadu_pd(p)); + auto pmask = (int64_t*)&mask; + data = _mm_set_pd (pmask[1] ? p[1] : 0.0, pmask[0] ? p[0] : 0.0); +#endif + } + SIMD (__m128d _data) { data = _data; } + + void Store (double * p) { _mm_storeu_pd(p, data); } + void Store (double * p, SIMD mask) + { +#ifdef __AVX__ + _mm_maskstore_pd(p, mask.Data(), data); +#else + /* + _mm_storeu_pd (p, _mm_or_pd (_mm_and_pd(_mm_castsi128_pd(mask.Data()), data), + _mm_andnot_pd(_mm_castsi128_pd(mask.Data()), _mm_loadu_pd(p)))); + */ + auto pmask = (int64_t*)&mask; + if (pmask[0]) p[0] = (*this)[0]; + if (pmask[1]) p[1] = (*this)[1]; +#endif + } + + template>::value, int>::type = 0> + SIMD (const T & func) + { + data = _mm_set_pd(func(1), func(0)); + } + + NETGEN_INLINE double operator[] (int i) const { return ((double*)(&data))[i]; } + NETGEN_INLINE __m128d Data() const { return data; } + NETGEN_INLINE __m128d & Data() { return data; } + + operator std::tuple () + { + auto pdata = (double*)&data; + return std::tuple(pdata[0], pdata[1]); + } + }; + + NETGEN_INLINE SIMD operator- (SIMD a) { return _mm_xor_pd(a.Data(), _mm_set1_pd(-0.0)); } + NETGEN_INLINE SIMD operator+ (SIMD a, SIMD b) { return _mm_add_pd(a.Data(),b.Data()); } + NETGEN_INLINE SIMD operator- (SIMD a, SIMD b) { return _mm_sub_pd(a.Data(),b.Data()); } + NETGEN_INLINE SIMD operator* (SIMD a, SIMD b) { return _mm_mul_pd(a.Data(),b.Data()); } + NETGEN_INLINE SIMD operator/ (SIMD a, SIMD b) { return _mm_div_pd(a.Data(),b.Data()); } + NETGEN_INLINE SIMD operator* (double a, SIMD b) { return _mm_set1_pd(a)*b; } + NETGEN_INLINE SIMD operator* (SIMD b, double a) { return _mm_set1_pd(a)*b; } + + template<> + NETGEN_INLINE auto Unpack (SIMD a, SIMD b) + { + return std::make_tuple(SIMD(_mm_unpacklo_pd(a.Data(),b.Data())), + SIMD(_mm_unpackhi_pd(a.Data(),b.Data()))); + } + + NETGEN_INLINE __m128d my_mm_hadd_pd(__m128d a, __m128d b) { +#if defined(__SSE3__) || defined(__AVX__) + return _mm_hadd_pd(a,b); +#else + return _mm_add_pd( _mm_unpacklo_pd(a,b), _mm_unpackhi_pd(a,b) ); +#endif + } + +#ifndef __AVX__ + NETGEN_INLINE __m128i my_mm_cmpgt_epi64(__m128i a, __m128i b) { + auto res_lo = _mm_cvtsi128_si64(a) > _mm_cvtsi128_si64(b) ? -1:0; + auto res_hi = _mm_cvtsi128_si64(_mm_srli_si128(a,8)) > _mm_cvtsi128_si64(_mm_srli_si128(b,8)) ? -1 : 0; + return _mm_set_epi64x(res_hi,res_lo); + } +#else + NETGEN_INLINE __m128i my_mm_cmpgt_epi64(__m128i a, __m128i b) { + return _mm_cmpgt_epi64(a,b); + } +#endif + + + NETGEN_INLINE SIMD sqrt (SIMD a) { return _mm_sqrt_pd(a.Data()); } + NETGEN_INLINE SIMD fabs (SIMD a) { return _mm_max_pd(a.Data(), (-a).Data()); } + using std::floor; + NETGEN_INLINE SIMD floor (SIMD a) + { return ngcore::SIMD([&](int i)->double { return floor(a[i]); } ); } + using std::ceil; + NETGEN_INLINE SIMD ceil (SIMD a) + { return ngcore::SIMD([&](int i)->double { return ceil(a[i]); } ); } + + NETGEN_INLINE SIMD operator<= (SIMD a , SIMD b) + { return _mm_castpd_si128( _mm_cmple_pd(a.Data(),b.Data())); } + NETGEN_INLINE SIMD operator< (SIMD a , SIMD b) + { return _mm_castpd_si128( _mm_cmplt_pd(a.Data(),b.Data())); } + NETGEN_INLINE SIMD operator>= (SIMD a , SIMD b) + { return _mm_castpd_si128( _mm_cmpge_pd(a.Data(),b.Data())); } + NETGEN_INLINE SIMD operator> (SIMD a , SIMD b) + { return _mm_castpd_si128( _mm_cmpgt_pd(a.Data(),b.Data())); } + NETGEN_INLINE SIMD operator== (SIMD a , SIMD b) + { return _mm_castpd_si128( _mm_cmpeq_pd(a.Data(),b.Data())); } + NETGEN_INLINE SIMD operator!= (SIMD a , SIMD b) + { return _mm_castpd_si128( _mm_cmpneq_pd(a.Data(),b.Data())); } + + NETGEN_INLINE SIMD operator<= (SIMD a , SIMD b) + { return _mm_xor_si128(_mm_cmpgt_epi64(a.Data(),b.Data()),_mm_set1_epi32(-1)); } + NETGEN_INLINE SIMD operator< (SIMD a , SIMD b) + { return my_mm_cmpgt_epi64(b.Data(),a.Data()); } + NETGEN_INLINE SIMD operator>= (SIMD a , SIMD b) + { return _mm_xor_si128(_mm_cmpgt_epi64(b.Data(),a.Data()),_mm_set1_epi32(-1)); } + NETGEN_INLINE SIMD operator> (SIMD a , SIMD b) + { return my_mm_cmpgt_epi64(a.Data(),b.Data()); } + NETGEN_INLINE SIMD operator== (SIMD a , SIMD b) + { return _mm_cmpeq_epi64(a.Data(),b.Data()); } + NETGEN_INLINE SIMD operator!= (SIMD a , SIMD b) + { return _mm_xor_si128(_mm_cmpeq_epi64(a.Data(),b.Data()),_mm_set1_epi32(-1)); } + + + + NETGEN_INLINE SIMD operator&& (SIMD a, SIMD b) + { return _mm_castpd_si128(_mm_and_pd (_mm_castsi128_pd(a.Data()),_mm_castsi128_pd( b.Data()))); } + NETGEN_INLINE SIMD operator|| (SIMD a, SIMD b) + { return _mm_castpd_si128(_mm_or_pd (_mm_castsi128_pd(a.Data()), _mm_castsi128_pd(b.Data()))); } + NETGEN_INLINE SIMD operator! (SIMD a) + { return _mm_castpd_si128(_mm_xor_pd (_mm_castsi128_pd(a.Data()),_mm_castsi128_pd( _mm_cmpeq_epi64(a.Data(),a.Data())))); } +#ifdef __SSE4_1__ + NETGEN_INLINE SIMD If (SIMD a, SIMD b, SIMD c) + { return _mm_blendv_pd(c.Data(), b.Data(), _mm_castsi128_pd(a.Data())); } +#else + NETGEN_INLINE SIMD If (SIMD a, SIMD b, SIMD c) + { + return _mm_or_pd( + _mm_andnot_pd(_mm_castsi128_pd(a.Data()),c.Data()), + _mm_and_pd(b.Data(),_mm_castsi128_pd(a.Data())) + );} +#endif // __SSE4_1__ + + NETGEN_INLINE SIMD IfPos (SIMD a, SIMD b, SIMD c) + { return ngcore::SIMD([&](int i)->double { return a[i]>0 ? b[i] : c[i]; }); } + NETGEN_INLINE SIMD IfZero (SIMD a, SIMD b, SIMD c) + { return ngcore::SIMD([&](int i)->double { return a[i]==0. ? b[i] : c[i]; }); } + + + NETGEN_INLINE double HSum (SIMD sd) + { + return _mm_cvtsd_f64 (my_mm_hadd_pd (sd.Data(), sd.Data())); + } + + NETGEN_INLINE auto HSum (SIMD sd1, SIMD sd2) + { + __m128d hv2 = my_mm_hadd_pd(sd1.Data(), sd2.Data()); + return SIMD (hv2); + // return SIMD(_mm_cvtsd_f64 (hv2), _mm_cvtsd_f64(_mm_shuffle_pd (hv2, hv2, 3))); + } + + NETGEN_INLINE SIMD If(SIMD a, SIMD b, + SIMD c) { + return _mm_or_si128( + _mm_andnot_si128(a.Data(),c.Data()), + _mm_and_si128(b.Data(),a.Data()) + ); + } + +} + +#endif // NETGEN_CORE_SIMD_SSE_HPP diff --git a/libsrc/general/CMakeLists.txt b/libsrc/general/CMakeLists.txt index 50cd53ce..cf1f4c63 100644 --- a/libsrc/general/CMakeLists.txt +++ b/libsrc/general/CMakeLists.txt @@ -11,7 +11,7 @@ target_sources(gen INTERFACE install(FILES ngarray.hpp autodiff.hpp autoptr.hpp ngbitarray.hpp dynamicmem.hpp hashtabl.hpp mpi_interface.hpp myadt.hpp - ngsimd.hpp mystring.hpp netgenout.hpp ngpython.hpp + mystring.hpp netgenout.hpp ngpython.hpp optmem.hpp parthreads.hpp seti.hpp sort.hpp spbita2d.hpp stack.hpp table.hpp template.hpp gzstream.h diff --git a/libsrc/general/myadt.hpp b/libsrc/general/myadt.hpp index 123bd04c..ad6fd1c4 100644 --- a/libsrc/general/myadt.hpp +++ b/libsrc/general/myadt.hpp @@ -47,7 +47,5 @@ namespace netgen #include "netgenout.hpp" #include "gzstream.h" -#include "ngsimd.hpp" - #endif diff --git a/libsrc/general/ngsimd.hpp b/libsrc/general/ngsimd.hpp deleted file mode 100644 index 9170e402..00000000 --- a/libsrc/general/ngsimd.hpp +++ /dev/null @@ -1,672 +0,0 @@ -#ifndef FILE_NGSIMD -#define FILE_NGSIMD -/**************************************************************************/ -/* File: ngsimd.hpp */ -/* Author: Joachim Schoeberl */ -/* Date: 25. Mar. 16 */ -/**************************************************************************/ - -#include -#include -#include -#include -#include -#include - -#include - -#ifdef WIN32 -#ifndef AVX_OPERATORS_DEFINED -#define AVX_OPERATORS_DEFINED -NG_INLINE __m128d operator- (__m128d a) { return _mm_xor_pd(a, _mm_set1_pd(-0.0)); } -NG_INLINE __m128d operator+ (__m128d a, __m128d b) { return _mm_add_pd(a,b); } -NG_INLINE __m128d operator- (__m128d a, __m128d b) { return _mm_sub_pd(a,b); } -NG_INLINE __m128d operator* (__m128d a, __m128d b) { return _mm_mul_pd(a,b); } -NG_INLINE __m128d operator/ (__m128d a, __m128d b) { return _mm_div_pd(a,b); } -NG_INLINE __m128d operator* (double a, __m128d b) { return _mm_set1_pd(a)*b; } -NG_INLINE __m128d operator* (__m128d b, double a) { return _mm_set1_pd(a)*b; } - -NG_INLINE __m128d operator+= (__m128d &a, __m128d b) { return a = a+b; } -NG_INLINE __m128d operator-= (__m128d &a, __m128d b) { return a = a-b; } -NG_INLINE __m128d operator*= (__m128d &a, __m128d b) { return a = a*b; } -NG_INLINE __m128d operator/= (__m128d &a, __m128d b) { return a = a/b; } - -NG_INLINE __m256d operator- (__m256d a) { return _mm256_xor_pd(a, _mm256_set1_pd(-0.0)); } -NG_INLINE __m256d operator+ (__m256d a, __m256d b) { return _mm256_add_pd(a,b); } -NG_INLINE __m256d operator- (__m256d a, __m256d b) { return _mm256_sub_pd(a,b); } -NG_INLINE __m256d operator* (__m256d a, __m256d b) { return _mm256_mul_pd(a,b); } -NG_INLINE __m256d operator/ (__m256d a, __m256d b) { return _mm256_div_pd(a,b); } -NG_INLINE __m256d operator* (double a, __m256d b) { return _mm256_set1_pd(a)*b; } -NG_INLINE __m256d operator* (__m256d b, double a) { return _mm256_set1_pd(a)*b; } - -NG_INLINE __m256d operator+= (__m256d &a, __m256d b) { return a = a+b; } -NG_INLINE __m256d operator-= (__m256d &a, __m256d b) { return a = a-b; } -NG_INLINE __m256d operator*= (__m256d &a, __m256d b) { return a = a*b; } -NG_INLINE __m256d operator/= (__m256d &a, __m256d b) { return a = a/b; } -#endif -#endif - - - -namespace ngsimd -{ - // MSVC does not define SSE. It's always present on 64bit cpus -#if (defined(_M_AMD64) || defined(_M_X64) || defined(__AVX__)) -#ifndef __SSE__ -#define __SSE__ -#endif -#ifndef __SSE2__ -#define __SSE2__ -#endif -#endif - - - constexpr int GetDefaultSIMDSize() { -#if defined __AVX512F__ - return 8; -#elif defined __AVX__ - return 4; -#elif defined __SSE__ - return 2; -#else - return 1; -#endif - } - -#if defined __AVX512F__ - typedef __m512 tAVX; - typedef __m512d tAVXd; -#elif defined __AVX__ - typedef __m256 tAVX; - typedef __m256d tAVXd; -#elif defined __SSE__ - typedef __m128 tAVX; - typedef __m128d tAVXd; -#endif - - - - template class SIMD; - - template - struct has_call_operator - { - template static std::true_type check( decltype( sizeof(&C::operator() )) ) { return std::true_type(); } - template static std::false_type check(...) { return std::false_type(); } - typedef decltype( check(sizeof(char)) ) type; - static constexpr type value = type(); - }; - - template - // a*b+c - NG_INLINE auto FMA(T1 a, T2 b, T3 c) - { - return a*b+c; - } - - template::value, int>::type = 0> - NG_INLINE SIMD operator+ (T a, SIMD b) { return SIMD(a) + b; } - template::value, int>::type = 0> - NG_INLINE SIMD operator- (T a, SIMD b) { return SIMD(a) - b; } - template::value, int>::type = 0> - NG_INLINE SIMD operator* (T a, SIMD b) { return SIMD(a) * b; } - template::value, int>::type = 0> - NG_INLINE SIMD operator/ (T a, SIMD b) { return SIMD(a) / b; } - template::value, int>::type = 0> - NG_INLINE SIMD operator+ (SIMD a, T b) { return a + SIMD(b); } - template::value, int>::type = 0> - NG_INLINE SIMD operator- (SIMD a, T b) { return a - SIMD(b); } - template::value, int>::type = 0> - NG_INLINE SIMD operator* (SIMD a, T b) { return a * SIMD(b); } - template::value, int>::type = 0> - NG_INLINE SIMD operator/ (SIMD a, T b) { return a / SIMD(b); } - - -using std::sqrt; -using std::fabs; - - class ExceptionNOSIMD : public std::runtime_error - { - public: - using std::runtime_error::runtime_error; - std::string What() { return what(); } - }; - - using std::exp; - template NG_INLINE SIMD exp (SIMD a) - { - return SIMD([&](int i)->double { return exp(a[i]); } ); - } - - using std::log; - template NG_INLINE SIMD log (SIMD a) - { - return SIMD([&](int i)->double { return log(a[i]); } ); - } - - using std::pow; - template NG_INLINE SIMD pow (SIMD a, double x) - { - return SIMD([&](int i)->double { return pow(a[i],x); } ); - } - - using std::sin; - template NG_INLINE SIMD sin (SIMD a) - { - return SIMD([&](int i)->double { return sin(a[i]); } ); - } - - using std::cos; - template NG_INLINE SIMD cos (SIMD a) - { - return SIMD([&](int i)->double { return cos(a[i]); } ); - } - - using std::tan; - template NG_INLINE SIMD tan (SIMD a) - { - return SIMD([&](int i)->double { return tan(a[i]); } ); - } - - using std::atan; - template NG_INLINE SIMD atan (SIMD a) - { - return SIMD([&](int i)->double { return atan(a[i]); } ); - } - - -///////////////////////////////////////////////////////////////////////////// -// SIMD width 1 (in case no AVX support is available) -///////////////////////////////////////////////////////////////////////////// - template<> - class SIMD - { - double data; - - public: - static constexpr int Size() { return 1; } - SIMD () = default; - SIMD (const SIMD &) = default; - SIMD & operator= (const SIMD &) = default; - - // only called if T has a call operator of appropriate type - template>::value, int>::type = 0> - SIMD (const T & func) - { - data = func(0); - } - - // only called if T is arithmetic (integral or floating point types) - template::value, int>::type = 0> - SIMD (const T & val) - { - data = val; - } - - SIMD (double const * p) - { - data = *p; - } - - NG_INLINE operator double() const { return data; } - NG_INLINE double operator[] (int i) const { return ((double*)(&data))[i]; } - NG_INLINE double Data() const { return data; } - NG_INLINE double & Data() { return data; } - - NG_INLINE SIMD &operator+= (SIMD b) { data+=b.Data(); return *this; } - NG_INLINE SIMD &operator-= (SIMD b) { data-=b.Data(); return *this; } - NG_INLINE SIMD &operator*= (SIMD b) { data*=b.Data(); return *this; } - NG_INLINE SIMD &operator/= (SIMD b) { data/=b.Data(); return *this; } - - }; - - NG_INLINE SIMD operator+ (SIMD a, SIMD b) { return a.Data()+b.Data(); } - NG_INLINE SIMD operator- (SIMD a, SIMD b) { return a.Data()-b.Data(); } - NG_INLINE SIMD operator- (SIMD a) { return -a.Data(); } - NG_INLINE SIMD operator* (SIMD a, SIMD b) { return a.Data()*b.Data(); } - NG_INLINE SIMD operator/ (SIMD a, SIMD b) { return a.Data()/b.Data(); } - - NG_INLINE SIMD sqrt (SIMD a) { return std::sqrt(a.Data()); } - NG_INLINE SIMD floor (SIMD a) { return std::floor(a.Data()); } - NG_INLINE SIMD ceil (SIMD a) { return std::ceil(a.Data()); } - NG_INLINE SIMD fabs (SIMD a) { return std::fabs(a.Data()); } - NG_INLINE SIMD L2Norm2 (SIMD a) { return a.Data()*a.Data(); } - NG_INLINE SIMD Trans (SIMD a) { return a; } - NG_INLINE SIMD IfPos (SIMD a, SIMD b, SIMD c) - { - return (a.Data() > 0) ? b : c; - } - - NG_INLINE double HSum (SIMD sd) - { - return sd.Data(); - } - - NG_INLINE auto HSum (SIMD sd1, SIMD sd2) - { - return std::make_tuple(sd1.Data(), sd2.Data()); - } - - NG_INLINE auto HSum (SIMD sd1, SIMD sd2, SIMD sd3, SIMD sd4) - { - return std::make_tuple(sd1.Data(), sd2.Data(), sd3.Data(), sd4.Data()); - } - - -///////////////////////////////////////////////////////////////////////////// -// SSE - Simd width 2 -///////////////////////////////////////////////////////////////////////////// -#ifdef __SSE__ - template<> - class alignas(16) SIMD - { - __m128d data; - - public: - static constexpr int Size() { return 2; } - SIMD () = default; - SIMD (const SIMD &) = default; - SIMD & operator= (const SIMD &) = default; - - SIMD (__m128d adata) - : data(adata) - { ; } - - // only called if T has a call operator of appropriate type - template>::value, int>::type = 0> - SIMD (const T & func) - { - data = _mm_set_pd(func(1), func(0)); - } - - // only called if T is arithmetic (integral or floating point types) - template::value, int>::type = 0> - SIMD (const T & val) - { - data = _mm_set1_pd(val); - } - - SIMD (double const * p) - { - data = _mm_loadu_pd(p); - } - - NG_INLINE operator __m128d() const { return data; } - NG_INLINE double operator[] (int i) const { return ((double*)(&data))[i]; } - NG_INLINE double& operator[] (int i) { return ((double*)(&data))[i]; } - NG_INLINE __m128d Data() const { return data; } - NG_INLINE __m128d & Data() { return data; } - - // NG_INLINE operator std::tuple () - // { return std::tuple((*this)[0], (*this)[1], (*this)[2], (*this)[3]); } - - - NG_INLINE SIMD &operator+= (SIMD b) { data+=b.Data(); return *this; } - NG_INLINE SIMD &operator-= (SIMD b) { data-=b.Data(); return *this; } - NG_INLINE SIMD &operator*= (SIMD b) { data*=b.Data(); return *this; } - NG_INLINE SIMD &operator/= (SIMD b) { data/=b.Data(); return *this; } - - }; - - NG_INLINE SIMD operator+ (SIMD a, SIMD b) { return a.Data()+b.Data(); } - NG_INLINE SIMD operator- (SIMD a, SIMD b) { return a.Data()-b.Data(); } - NG_INLINE SIMD operator- (SIMD a) { return -a.Data(); } - NG_INLINE SIMD operator* (SIMD a, SIMD b) { return a.Data()*b.Data(); } - NG_INLINE SIMD operator/ (SIMD a, SIMD b) { return a.Data()/b.Data(); } - - /* - NG_INLINE SIMD sqrt (SIMD a) { return _mm256_sqrt_pd(a.Data()); } - NG_INLINE SIMD floor (SIMD a) { return _mm256_floor_pd(a.Data()); } - NG_INLINE SIMD ceil (SIMD a) { return _mm256_ceil_pd(a.Data()); } - NG_INLINE SIMD fabs (SIMD a) { return _mm256_max_pd(a.Data(), -a.Data()); } - NG_INLINE SIMD L2Norm2 (SIMD a) { return a.Data()*a.Data(); } - NG_INLINE SIMD Trans (SIMD a) { return a; } - NG_INLINE SIMD IfPos (SIMD a, SIMD b, SIMD c) - { - auto cp = _mm256_cmp_pd (a.Data(), _mm256_setzero_pd(), _CMP_GT_OS); - return _mm256_blendv_pd(c.Data(), b.Data(), cp); - } - - NG_INLINE double HSum (SIMD sd) - { - __m128d hv = _mm_add_pd (_mm256_extractf128_pd(sd.Data(),0), _mm256_extractf128_pd(sd.Data(),1)); - return _mm_cvtsd_f64 (_mm_hadd_pd (hv, hv)); - } - - NG_INLINE auto HSum (SIMD sd1, SIMD sd2) - { - __m256d hv = _mm256_hadd_pd(sd1.Data(), sd2.Data()); - __m128d hv2 = _mm_add_pd (_mm256_extractf128_pd(hv,0), _mm256_extractf128_pd(hv,1)); - return std::make_tuple(_mm_cvtsd_f64 (hv2), _mm_cvtsd_f64(_mm_shuffle_pd (hv2, hv2, 3))); - } - - NG_INLINE auto HSum (SIMD v1, SIMD v2, SIMD v3, SIMD v4) - { - __m256d hsum1 = _mm256_hadd_pd (v1.Data(), v2.Data()); - __m256d hsum2 = _mm256_hadd_pd (v3.Data(), v4.Data()); - __m256d hsum = _mm256_add_pd (_mm256_permute2f128_pd (hsum1, hsum2, 1+2*16), - _mm256_blend_pd (hsum1, hsum2, 12)); - return SIMD(hsum); - } - */ -#endif // __SSE__ - - - -///////////////////////////////////////////////////////////////////////////// -// AVX - Simd width 4 -///////////////////////////////////////////////////////////////////////////// -#ifdef __AVX__ - template<> - class alignas(32) SIMD - { - __m256d data; - - public: - static constexpr int Size() { return 4; } - SIMD () = default; - SIMD (const SIMD &) = default; - SIMD & operator= (const SIMD &) = default; - - SIMD (__m256d adata) - : data(adata) - { ; } - - // only called if T has a call operator of appropriate type - template>::value, int>::type = 0> - SIMD (const T & func) - { - data = _mm256_set_pd(func(3), func(2), func(1), func(0)); - } - - // only called if T is arithmetic (integral or floating point types) - template::value, int>::type = 0> - SIMD (const T & val) - { - data = _mm256_set1_pd(val); - } - - SIMD (double const * p) - { - data = _mm256_loadu_pd(p); - } - - NG_INLINE operator __m256d() const { return data; } - NG_INLINE double operator[] (int i) const { return ((double*)(&data))[i]; } - NG_INLINE double& operator[] (int i) { return ((double*)(&data))[i]; } - NG_INLINE __m256d Data() const { return data; } - NG_INLINE __m256d & Data() { return data; } - - NG_INLINE operator std::tuple () - { return std::tuple((*this)[0], (*this)[1], (*this)[2], (*this)[3]); } - - - NG_INLINE SIMD &operator+= (SIMD b) { data+=b.Data(); return *this; } - NG_INLINE SIMD &operator-= (SIMD b) { data-=b.Data(); return *this; } - NG_INLINE SIMD &operator*= (SIMD b) { data*=b.Data(); return *this; } - NG_INLINE SIMD &operator/= (SIMD b) { data/=b.Data(); return *this; } - - }; - - NG_INLINE SIMD operator+ (SIMD a, SIMD b) { return a.Data()+b.Data(); } - NG_INLINE SIMD operator- (SIMD a, SIMD b) { return a.Data()-b.Data(); } - NG_INLINE SIMD operator- (SIMD a) { return -a.Data(); } - NG_INLINE SIMD operator* (SIMD a, SIMD b) { return a.Data()*b.Data(); } - NG_INLINE SIMD operator/ (SIMD a, SIMD b) { return a.Data()/b.Data(); } - - NG_INLINE SIMD sqrt (SIMD a) { return _mm256_sqrt_pd(a.Data()); } - NG_INLINE SIMD floor (SIMD a) { return _mm256_floor_pd(a.Data()); } - NG_INLINE SIMD ceil (SIMD a) { return _mm256_ceil_pd(a.Data()); } - NG_INLINE SIMD fabs (SIMD a) { return _mm256_max_pd(a.Data(), -a.Data()); } - NG_INLINE SIMD L2Norm2 (SIMD a) { return a.Data()*a.Data(); } - NG_INLINE SIMD Trans (SIMD a) { return a; } - NG_INLINE SIMD IfPos (SIMD a, SIMD b, SIMD c) - { - auto cp = _mm256_cmp_pd (a.Data(), _mm256_setzero_pd(), _CMP_GT_OS); - return _mm256_blendv_pd(c.Data(), b.Data(), cp); - } - - NG_INLINE double HSum (SIMD sd) - { - __m128d hv = _mm_add_pd (_mm256_extractf128_pd(sd.Data(),0), _mm256_extractf128_pd(sd.Data(),1)); - return _mm_cvtsd_f64 (_mm_hadd_pd (hv, hv)); - } - - NG_INLINE auto HSum (SIMD sd1, SIMD sd2) - { - __m256d hv = _mm256_hadd_pd(sd1.Data(), sd2.Data()); - __m128d hv2 = _mm_add_pd (_mm256_extractf128_pd(hv,0), _mm256_extractf128_pd(hv,1)); - return std::make_tuple(_mm_cvtsd_f64 (hv2), _mm_cvtsd_f64(_mm_shuffle_pd (hv2, hv2, 3))); - } - - NG_INLINE auto HSum (SIMD v1, SIMD v2, SIMD v3, SIMD v4) - { - __m256d hsum1 = _mm256_hadd_pd (v1.Data(), v2.Data()); - __m256d hsum2 = _mm256_hadd_pd (v3.Data(), v4.Data()); - __m256d hsum = _mm256_add_pd (_mm256_permute2f128_pd (hsum1, hsum2, 1+2*16), - _mm256_blend_pd (hsum1, hsum2, 12)); - return SIMD(hsum); - } - -#endif // __AVX__ - -///////////////////////////////////////////////////////////////////////////// -// AVX512 - Simd width 8 -///////////////////////////////////////////////////////////////////////////// -#ifdef __AVX512F__ - template<> - class alignas(64) SIMD - { - __m512d data; - - public: - static constexpr int Size() { return 8; } - SIMD () = default; - SIMD (const SIMD &) = default; - SIMD & operator= (const SIMD &) = default; - - SIMD (__m512d adata) - : data(adata) - { ; } - - // only called if T has a call operator of appropriate type - template>::value, int>::type = 0> - SIMD (const T & func) - { - data = _mm512_set_pd(func(7), func(6), func(5), func(4), - func(3), func(2), func(1), func(0)); - } - - // only called if T is arithmetic (integral or floating point types) - template::value, int>::type = 0> - SIMD (const T & val) - { - data = _mm512_set1_pd(val); - } - - SIMD (double const * p) - { - data = _mm512_loadu_pd(p); - } - - NG_INLINE operator __m512d() const { return data; } - NG_INLINE double operator[] (int i) const { return ((double*)(&data))[i]; } - NG_INLINE __m512d Data() const { return data; } - NG_INLINE __m512d & Data() { return data; } - - NG_INLINE SIMD &operator+= (SIMD b) { data+=b.Data(); return *this; } - NG_INLINE SIMD &operator-= (SIMD b) { data-=b.Data(); return *this; } - NG_INLINE SIMD &operator*= (SIMD b) { data*=b.Data(); return *this; } - NG_INLINE SIMD &operator/= (SIMD b) { data/=b.Data(); return *this; } - - }; - - NG_INLINE SIMD operator- (SIMD a) { return _mm512_sub_pd(_mm512_setzero_pd(), a.Data()); } - - NG_INLINE SIMD operator+ (SIMD a, SIMD b) { return _mm512_add_pd(a.Data(),b.Data()); } - NG_INLINE SIMD operator- (SIMD a, SIMD b) { return _mm512_sub_pd(a.Data(),b.Data()); } - NG_INLINE SIMD operator* (SIMD a, SIMD b) { return _mm512_mul_pd(a.Data(),b.Data()); } - NG_INLINE SIMD operator/ (SIMD a, SIMD b) { return _mm512_div_pd(a.Data(),b.Data()); } - - NG_INLINE SIMD sqrt (SIMD a) { return _mm512_sqrt_pd(a.Data()); } - NG_INLINE SIMD floor (SIMD a) { return _mm512_floor_pd(a.Data()); } - NG_INLINE SIMD ceil (SIMD a) { return _mm512_ceil_pd(a.Data()); } - NG_INLINE SIMD fabs (SIMD a) { return _mm512_max_pd(a.Data(), -a.Data()); } - NG_INLINE SIMD L2Norm2 (SIMD a) { return a.Data()*a.Data(); } - NG_INLINE SIMD Trans (SIMD a) { return a; } - NG_INLINE SIMD IfPos (SIMD a, SIMD b, SIMD c) - { - auto cp = _mm512_cmp_pd_mask (a.Data(), _mm512_setzero_pd(), _MM_CMPINT_GT); - return _mm512_mask_blend_pd(cp, c.Data(), b.Data()); - } - - - template<> NG_INLINE auto FMA (SIMD a, SIMD b, SIMD c) - { - return _mm512_fmadd_pd (a.Data(), b.Data(), c.Data()); - } - - NG_INLINE double HSum (SIMD sd) - { - SIMD low = _mm512_extractf64x4_pd(sd.Data(),0); - SIMD high = _mm512_extractf64x4_pd(sd.Data(),1); - return HSum(low)+HSum(high); - } - - NG_INLINE auto HSum (SIMD sd1, SIMD sd2) - { - return std::make_tuple(HSum(sd1), HSum(sd2)); - } - - NG_INLINE SIMD HSum (SIMD v1, SIMD v2, SIMD v3, SIMD v4) - { - SIMD high1 = _mm512_extractf64x4_pd(v1.Data(),1); - SIMD high2 = _mm512_extractf64x4_pd(v2.Data(),1); - SIMD high3 = _mm512_extractf64x4_pd(v3.Data(),1); - SIMD high4 = _mm512_extractf64x4_pd(v4.Data(),1); - SIMD low1 = _mm512_extractf64x4_pd(v1.Data(),0); - SIMD low2 = _mm512_extractf64x4_pd(v2.Data(),0); - SIMD low3 = _mm512_extractf64x4_pd(v3.Data(),0); - SIMD low4 = _mm512_extractf64x4_pd(v4.Data(),0); - return HSum(low1,low2,low3,low4) + HSum(high1,high2,high3,high4); - } -#endif // __AVX512F__ - - -//////////////////////////////////////////////////////////////////////////////// -// MultiSIMD - Multiple SIMD values in one struct using head-tail implementation -//////////////////////////////////////////////////////////////////////////////// - template - class MultiSIMD - { - SIMD head; - MultiSIMD tail; - public: - MultiSIMD () = default; - MultiSIMD (const MultiSIMD & ) = default; - MultiSIMD (T v) : head(v), tail(v) { ; } - MultiSIMD (SIMD _head, MultiSIMD _tail) - : head(_head), tail(_tail) { ; } - SIMD Head() const { return head; } - MultiSIMD Tail() const { return tail; } - SIMD & Head() { return head; } - MultiSIMD & Tail() { return tail; } - - template - SIMD Get() const { return NR==0 ? head : tail.template Get(); } - template - SIMD & Get() { return NR==0 ? head : tail.template Get(); } - auto MakeTuple() { return std::tuple_cat(std::tuple&> (head), tail.MakeTuple()); } - // not yet possible for MSVC - // operator auto () { return MakeTuple(); } - }; - - template - class MultiSIMD<2,T> - { - SIMD v0, v1; - public: - MultiSIMD () = default; - MultiSIMD (const MultiSIMD & ) = default; - MultiSIMD (T v) : v0(v), v1(v) { ; } - MultiSIMD (SIMD _v0, SIMD _v1) : v0(_v0), v1(_v1) { ; } - - SIMD Head() const { return v0; } - SIMD Tail() const { return v1; } - SIMD & Head() { return v0; } - SIMD & Tail() { return v1; } - - template - SIMD Get() const { return NR==0 ? v0 : v1; } - template - SIMD & Get() { return NR==0 ? v0 : v1; } - auto MakeTuple() { return std::tuple&, SIMD&> (v0, v1); } - operator std::tuple&, SIMD&>() { return MakeTuple(); } - }; - - template NG_INLINE MultiSIMD operator+ (MultiSIMD a, MultiSIMD b) - { return MultiSIMD (a.Head()+b.Head(), a.Tail()+b.Tail()); } - template NG_INLINE MultiSIMD operator+ (double a, MultiSIMD b) - { return MultiSIMD (a+b.Head(), a+b.Tail()); } - template NG_INLINE MultiSIMD operator+ (MultiSIMD b, double a) - { return MultiSIMD (a+b.Head(), a+b.Tail()); } - - template NG_INLINE MultiSIMD operator- (MultiSIMD a, MultiSIMD b) - { return MultiSIMD (a.Head()-b.Head(), a.Tail()-b.Tail()); } - template NG_INLINE MultiSIMD operator- (double a, MultiSIMD b) - { return MultiSIMD (a-b.Head(), a-b.Tail()); } - template NG_INLINE MultiSIMD operator- (MultiSIMD b, double a) - { return MultiSIMD (b.Head()-a, b.Tail()-a); } - template NG_INLINE MultiSIMD operator- (MultiSIMD a) - { return MultiSIMD (-a.Head(), -a.Tail()); } - template NG_INLINE MultiSIMD operator* (MultiSIMD a, MultiSIMD b) - { return MultiSIMD (a.Head()*b.Head(), a.Tail()*b.Tail()); } - template NG_INLINE MultiSIMD operator/ (MultiSIMD a, MultiSIMD b) - { return MultiSIMD (a.Head()/b.Head(), a.Tail()/b.Tail()); } - template NG_INLINE MultiSIMD operator* (double a, MultiSIMD b) - { return MultiSIMD ( a*b.Head(), a*b.Tail()); } - template NG_INLINE MultiSIMD operator* (MultiSIMD b, double a) - { return MultiSIMD ( a*b.Head(), a*b.Tail()); } - - template NG_INLINE MultiSIMD & operator+= (MultiSIMD & a, MultiSIMD b) - { a.Head()+=b.Head(); a.Tail()+=b.Tail(); return a; } - template NG_INLINE MultiSIMD operator-= (MultiSIMD & a, double b) - { a.Head()-=b; a.Tail()-=b; return a; } - template NG_INLINE MultiSIMD operator-= (MultiSIMD & a, MultiSIMD b) - { a.Head()-=b.Head(); a.Tail()-=b.Tail(); return a; } - template NG_INLINE MultiSIMD & operator*= (MultiSIMD & a, MultiSIMD b) - { a.Head()*=b.Head(); a.Tail()*=b.Tail(); return a; } - template NG_INLINE MultiSIMD & operator*= (MultiSIMD & a, double b) - { a.Head()*=b; a.Tail()*=b; return a; } - // NG_INLINE MultiSIMD operator/= (MultiSIMD & a, MultiSIMD b) { return a.Data()/=b.Data(); } - - NG_INLINE SIMD HVSum (SIMD a) { return a; } - template - NG_INLINE SIMD HVSum (MultiSIMD a) { return a.Head() + HVSum(a.Tail()); } - - template NG_INLINE double HSum (MultiSIMD a) { return HSum(HVSum(a)); } - template NG_INLINE auto HSum (MultiSIMD a, MultiSIMD b) - { return HSum(HVSum(a), HVSum(b)); } - - template - std::ostream & operator<< (std::ostream & ost, MultiSIMD multi) - { - ost << multi.Head() << " " << multi.Tail(); - return ost; - } - - template - std::ostream & operator<< (std::ostream & ost, SIMD simd) - { - ost << simd[0]; - for (int i = 1; i < simd.Size(); i++) - ost << " " << simd[i]; - return ost; - } -} - -namespace netgen -{ - using namespace ngsimd; -} -#endif diff --git a/libsrc/interface/nginterface_v2.cpp b/libsrc/interface/nginterface_v2.cpp index a276f376..18563f91 100644 --- a/libsrc/interface/nginterface_v2.cpp +++ b/libsrc/interface/nginterface_v2.cpp @@ -779,29 +779,23 @@ namespace netgen -#ifdef __SSE__ -#include - template<> DLL_HEADER void Ngx_Mesh :: MultiElementTransformation<1,1> (int elnr, int npts, - const tAVXd * xi, size_t sxi, - tAVXd * x, size_t sx, - tAVXd * dxdxi, size_t sdxdxi) const + const SIMD * xi, size_t sxi, + SIMD * x, size_t sx, + SIMD * dxdxi, size_t sdxdxi) const { cout << "multi-eltrafo simd called, 1,1,simd" << endl; } template<> DLL_HEADER void Ngx_Mesh :: MultiElementTransformation<2,2> (int elnr, int npts, - const tAVXd * xi, size_t sxi, - tAVXd * x, size_t sx, - tAVXd * dxdxi, size_t sdxdxi) const + const SIMD * xi, size_t sxi, + SIMD * x, size_t sx, + SIMD * dxdxi, size_t sdxdxi) const { mesh->GetCurvedElements().CalcMultiPointSurfaceTransformation<2> - (elnr, npts, - reinterpret_cast*> (xi), sxi, - reinterpret_cast*> (x), sx, - reinterpret_cast*> (dxdxi), sdxdxi); + (elnr, npts, xi, sxi, x, sx, dxdxi, sdxdxi); /* for (int i = 0; i < npts; i++) { @@ -828,15 +822,15 @@ namespace netgen template<> DLL_HEADER void Ngx_Mesh :: MultiElementTransformation<3,3> (int elnr, int npts, - const tAVXd * xi, size_t sxi, - tAVXd * x, size_t sx, - tAVXd * dxdxi, size_t sdxdxi) const + const SIMD * xi, size_t sxi, + SIMD * x, size_t sx, + SIMD * dxdxi, size_t sdxdxi) const { mesh->GetCurvedElements().CalcMultiPointElementTransformation (elnr, npts, - reinterpret_cast*> (xi), sxi, - reinterpret_cast*> (x), sx, - reinterpret_cast*> (dxdxi), sdxdxi); + xi, sxi, + x, sx, + dxdxi, sdxdxi); /* for (int i = 0; i < npts; i++) { @@ -863,33 +857,30 @@ namespace netgen template<> DLL_HEADER void Ngx_Mesh :: MultiElementTransformation<0,2> (int elnr, int npts, - const tAVXd *xi, size_t sxi, - tAVXd * x, size_t sx, - tAVXd * dxdxi, size_t sdxdxi) const + const SIMD *xi, size_t sxi, + SIMD * x, size_t sx, + SIMD * dxdxi, size_t sdxdxi) const { cout << "MultiElementtransformation<0,2> simd not implemented" << endl; } template<> DLL_HEADER void Ngx_Mesh :: MultiElementTransformation<0,1> (int elnr, int npts, - const tAVXd * xi, size_t sxi, - tAVXd * x, size_t sx, - tAVXd * dxdxi, size_t sdxdxi) const + const SIMD * xi, size_t sxi, + SIMD * x, size_t sx, + SIMD * dxdxi, size_t sdxdxi) const { cout << "multi-eltrafo simd called, 0,1,simd" << endl; } template<> DLL_HEADER void Ngx_Mesh :: MultiElementTransformation<1,3> (int elnr, int npts, - const tAVXd * xi, size_t sxi, - tAVXd * x, size_t sx, - tAVXd * dxdxi, size_t sdxdxi) const + const SIMD * xi, size_t sxi, + SIMD * x, size_t sx, + SIMD * dxdxi, size_t sdxdxi) const { mesh->GetCurvedElements().CalcMultiPointSegmentTransformation<3> - (elnr, npts, - reinterpret_cast*> (xi), sxi, - reinterpret_cast*> (x), sx, - reinterpret_cast*> (dxdxi), sdxdxi); + (elnr, npts, xi, sxi, x, sx, dxdxi, sdxdxi); /* double hxi[4][1]; double hx[4][3]; @@ -912,15 +903,12 @@ namespace netgen template<> DLL_HEADER void Ngx_Mesh :: MultiElementTransformation<1,2> (int elnr, int npts, - const tAVXd * xi, size_t sxi, - tAVXd * x, size_t sx, - tAVXd * dxdxi, size_t sdxdxi) const + const SIMD * xi, size_t sxi, + SIMD * x, size_t sx, + SIMD * dxdxi, size_t sdxdxi) const { mesh->GetCurvedElements().CalcMultiPointSegmentTransformation<2> - (elnr, npts, - reinterpret_cast*> (xi), sxi, - reinterpret_cast*> (x), sx, - reinterpret_cast*> (dxdxi), sdxdxi); + (elnr, npts, xi, sxi, x, sx, dxdxi, sdxdxi); /* for (int i = 0; i < npts; i++) { @@ -947,15 +935,12 @@ namespace netgen template<> DLL_HEADER void Ngx_Mesh :: MultiElementTransformation<2,3> (int elnr, int npts, - const tAVXd * xi, size_t sxi, - tAVXd * x, size_t sx, - tAVXd * dxdxi, size_t sdxdxi) const + const SIMD * xi, size_t sxi, + SIMD * x, size_t sx, + SIMD * dxdxi, size_t sdxdxi) const { mesh->GetCurvedElements().CalcMultiPointSurfaceTransformation<3> - (elnr, npts, - reinterpret_cast*> (xi), sxi, - reinterpret_cast*> (x), sx, - reinterpret_cast*> (dxdxi), sdxdxi); + (elnr, npts, xi, sxi, x, sx, dxdxi, sdxdxi); /* for (int i = 0; i < npts; i++) { @@ -982,9 +967,9 @@ namespace netgen template<> DLL_HEADER void Ngx_Mesh :: MultiElementTransformation<0,3> (int elnr, int npts, - const tAVXd * xi, size_t sxi, - tAVXd * x, size_t sx, - tAVXd * dxdxi, size_t sdxdxi) const + const SIMD * xi, size_t sxi, + SIMD * x, size_t sx, + SIMD * dxdxi, size_t sdxdxi) const { for (int i = 0; i < npts; i++) { @@ -1003,10 +988,6 @@ namespace netgen } } - -#endif - - diff --git a/libsrc/visualization/soldata.hpp b/libsrc/visualization/soldata.hpp index c522f1a3..6a5c5626 100644 --- a/libsrc/visualization/soldata.hpp +++ b/libsrc/visualization/soldata.hpp @@ -6,15 +6,6 @@ namespace netgen { using namespace std; - /* -#if defined __AVX512F__ - typedef __m512 tAVX; - typedef __m512d tAVXd; -#elif defined __AVX__ - typedef __m256 tAVX; - typedef __m256d tAVXd; -#endif - */ class SolutionData { @@ -101,17 +92,15 @@ namespace netgen return res; } -#ifdef __SSE__ virtual bool GetMultiSurfValue (size_t selnr, size_t facetnr, size_t npts, - const ngsimd::tAVXd * xref, - const ngsimd::tAVXd * x, - const ngsimd::tAVXd * dxdxref, - ngsimd::tAVXd * values) + const SIMD * xref, + const SIMD * x, + const SIMD * dxdxref, + SIMD * values) { cerr << "GetMultiSurfVaue not overloaded for SIMD" << endl; return false; } -#endif virtual bool GetSegmentValue (int segnr, double xref, double * values) { return false; } From fc44eb95dfdb09c458c8c046b8249d2520944886 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Fri, 11 Dec 2020 23:12:34 +0100 Subject: [PATCH 281/384] simd - array and variadic ctor --- libsrc/core/simd_avx.hpp | 6 +++ libsrc/core/simd_avx512.hpp | 4 +- libsrc/core/simd_generic.hpp | 101 ++++++++++++++++++++++++++++------- libsrc/core/simd_sse.hpp | 6 +++ 4 files changed, 96 insertions(+), 21 deletions(-) diff --git a/libsrc/core/simd_avx.hpp b/libsrc/core/simd_avx.hpp index 92ac6c04..c845ee2c 100644 --- a/libsrc/core/simd_avx.hpp +++ b/libsrc/core/simd_avx.hpp @@ -73,6 +73,9 @@ namespace ngcore SIMD (int64_t val) { data = _mm256_set1_epi64x(val); } SIMD (int64_t v0, int64_t v1, int64_t v2, int64_t v3) { data = _mm256_set_epi64x(v3,v2,v1,v0); } + SIMD (std::array a) + : data{_mm256_set_epi64x(a[3],a[2],a[1],a[0])} + {} // SIMD (SIMD v0, SIMD v1) : SIMD(v0[0], v0[1], v1[0], v1[1]) { ; } SIMD (__m256i _data) { data = _data; } @@ -123,6 +126,9 @@ namespace ngcore SIMD (double const * p) { data = _mm256_loadu_pd(p); } SIMD (double const * p, SIMD mask) { data = _mm256_maskload_pd(p, mask.Data()); } SIMD (__m256d _data) { data = _data; } + SIMD (std::array a) + : data{_mm256_set_pd(a[3],a[2],a[1],a[0])} + {} void Store (double * p) { _mm256_storeu_pd(p, data); } void Store (double * p, SIMD mask) { _mm256_maskstore_pd(p, mask.Data(), data); } diff --git a/libsrc/core/simd_avx512.hpp b/libsrc/core/simd_avx512.hpp index 4c461371..1f06e826 100644 --- a/libsrc/core/simd_avx512.hpp +++ b/libsrc/core/simd_avx512.hpp @@ -214,9 +214,9 @@ namespace ngcore NETGEN_INLINE SIMD HSum (SIMD v1, SIMD v2, SIMD v3, SIMD v4) { SIMD lo,hi; - tie(lo,hi) = Unpack(v1, v2); + std::tie(lo,hi) = Unpack(v1, v2); SIMD sum01 = lo+hi; - tie(lo,hi) = Unpack(v3, v4); + std::tie(lo,hi) = Unpack(v3, v4); SIMD sum23 = lo+hi; // sum01 b a b a b a b a // sum23 d c d c d c d c diff --git a/libsrc/core/simd_generic.hpp b/libsrc/core/simd_generic.hpp index 8cebe30b..027b0f14 100644 --- a/libsrc/core/simd_generic.hpp +++ b/libsrc/core/simd_generic.hpp @@ -15,7 +15,6 @@ namespace ngcore { - using namespace ngcore; constexpr int GetDefaultSIMDSize() { #if defined __AVX512F__ @@ -34,6 +33,23 @@ namespace ngcore class mask64; + //////////////////////////////////////////////////////////////////////////// + namespace detail { + template + auto array_range_impl(std::array const& arr, + size_t first, + std::index_sequence) + -> std::array { + return {arr[first + I]...}; + } + + template + auto array_range(std::array const& arr, size_t first) { + return array_range_impl(arr, first, std::make_index_sequence{}); + } + + } // namespace detail + //////////////////////////////////////////////////////////////////////////// // mask @@ -89,10 +105,19 @@ namespace ngcore SIMD (const SIMD &) = default; SIMD & operator= (const SIMD &) = default; SIMD (int64_t val) { data = val; } + SIMD (std::array arr) + : data{arr[0]} + {} int64_t operator[] (int i) const { return ((int64_t*)(&data))[i]; } auto Data() const { return data; } static SIMD FirstInt(int64_t n0=0) { return {n0}; } + template + int64_t Get() + { + static_assert(I==0); + return data; + } }; template @@ -114,6 +139,20 @@ namespace ngcore SIMD (int64_t val) : lo{val}, high{val} { ; } SIMD (SIMD lo_, SIMD high_) : lo(lo_), high(high_) { ; } + SIMD( std::array arr ) + : lo(detail::array_range(arr, 0)), + high(detail::array_range(arr, N1)) + {} + + template + SIMD(const T... vals) + : lo(detail::array_range(std::array{vals...}, 0)), + high(detail::array_range(std::array{vals...}, N1)) + { + static_assert(sizeof...(vals)==N, "wrong number of arguments"); + } + + template>::value, int>::type = 0> SIMD (const T & func) { @@ -137,6 +176,13 @@ namespace ngcore static SIMD FirstInt() { return { 0, 1, 2, 3 }; } */ static SIMD FirstInt(int64_t n0=0) { return {SIMD::FirstInt(n0), SIMD::FirstInt(n0+N1)}; } + template + int64_t Get() + { + static_assert(I>=0 && I(); + else return high.template Get(); + } }; @@ -158,6 +204,9 @@ namespace ngcore SIMD (size_t val) { data = val; } SIMD (double const * p) { data = *p; } SIMD (double const * p, SIMD mask) { data = mask.Data() ? *p : 0.0; } + SIMD (std::array arr) + : data{arr[0]} + {} template >::value,int>::type = 0> SIMD (const T & func) @@ -177,8 +226,15 @@ namespace ngcore double operator[] (int i) const { return ((double*)(&data))[i]; } double Data() const { return data; } + template + double Get() + { + static_assert(I==0); + return data; + } }; + template class SIMD { @@ -194,22 +250,6 @@ namespace ngcore SIMD (const SIMD &) = default; SIMD (SIMD lo_, SIMD hi_) : lo(lo_), high(hi_) { ; } - template> - SIMD (double v0, double v1, double v2, double v3) - { - if constexpr(N1==1) - { - lo = v0; - high = {v1,v2,v3}; - } - if constexpr(N1==2) - { - lo = {v0,v1}; - high = {v2,v3}; - - } - } - template >::value,int>::type = 0> SIMD (const T & func) { @@ -240,6 +280,23 @@ namespace ngcore SIMD (double const * p, SIMD mask) : lo{p, mask.Lo()}, high{p+N1, mask.Hi()} { } + SIMD (double * p) : lo{p}, high{p+N1} { ; } + SIMD (double * p, SIMD mask) + : lo{p, mask.Lo()}, high{p+N1, mask.Hi()} + { } + + SIMD( std::array arr ) + : lo(detail::array_range(arr, 0)), + high(detail::array_range(arr, N1)) + {} + + template + SIMD(const T... vals) + : lo(detail::array_range(std::array{vals...}, 0)), + high(detail::array_range(std::array{vals...}, N1)) + { + static_assert(sizeof...(vals)==N, "wrong number of arguments"); + } void Store (double * p) { lo.Store(p); high.Store(p+N1); } void Store (double * p, SIMD mask) @@ -261,6 +318,13 @@ namespace ngcore operator std::tuple () { return std::tuple((*this)[0], (*this)[1], (*this)[2], (*this)[3]); } + template + double Get() + { + static_assert(I>=0 && I(); + else return high.template Get(); + } }; @@ -582,10 +646,9 @@ namespace ngcore } } - - } + namespace std { // structured binding support diff --git a/libsrc/core/simd_sse.hpp b/libsrc/core/simd_sse.hpp index 6ea3f021..300ddc0b 100644 --- a/libsrc/core/simd_sse.hpp +++ b/libsrc/core/simd_sse.hpp @@ -48,6 +48,9 @@ namespace ngcore SIMD () {} SIMD (const SIMD &) = default; SIMD (int64_t v0, int64_t v1) { data = _mm_set_epi64x(v1,v0); } + SIMD (std::array arr) + : data{_mm_set_epi64x(arr[1],arr[0])} + {} SIMD & operator= (const SIMD &) = default; @@ -83,6 +86,9 @@ NETGEN_INLINE SIMD operator- (SIMD a, SIMD b) { SIMD () {} SIMD (const SIMD &) = default; SIMD (double v0, double v1) { data = _mm_set_pd(v1,v0); } + SIMD (std::array arr) + : data{_mm_set_pd(arr[1], arr[0])} + {} SIMD & operator= (const SIMD &) = default; From 248145bbf098db391a0db7b5df4e7dcc45055808 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Mon, 14 Dec 2020 12:47:45 +0100 Subject: [PATCH 282/384] fix wrong simd operators --- libsrc/core/simd_generic.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libsrc/core/simd_generic.hpp b/libsrc/core/simd_generic.hpp index 027b0f14..4fc47c33 100644 --- a/libsrc/core/simd_generic.hpp +++ b/libsrc/core/simd_generic.hpp @@ -338,7 +338,7 @@ namespace ngcore template NETGEN_INLINE SIMD operator- (SIMD a, SIMD b) { if constexpr(N==1) return a.Data()-b.Data(); - else return { a.Lo()-b.Lo(), a.Hi()+b.Hi() }; + else return { a.Lo()-b.Lo(), a.Hi()-b.Hi() }; } template NETGEN_INLINE SIMD operator- (SIMD a) { @@ -349,13 +349,13 @@ namespace ngcore template NETGEN_INLINE SIMD operator* (SIMD a, SIMD b) { if constexpr(N==1) return a.Data()*b.Data(); - else return { a.Lo()*b.Lo(), a.Hi()+b.Hi() }; + else return { a.Lo()*b.Lo(), a.Hi()*b.Hi() }; } template NETGEN_INLINE SIMD operator/ (SIMD a, SIMD b) { if constexpr(N==1) return a.Data()/b.Data(); - else return { a.Lo()/b.Lo(), a.Hi()+b.Hi() }; + else return { a.Lo()/b.Lo(), a.Hi()/b.Hi() }; } template From f213a7a5b1b3ab4bd8f5ae4cbb747d14360a15e7 Mon Sep 17 00:00:00 2001 From: mhochsteger Date: Mon, 14 Dec 2020 15:50:27 +0100 Subject: [PATCH 283/384] fix fabs for AVX on Windows --- libsrc/core/simd_avx.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsrc/core/simd_avx.hpp b/libsrc/core/simd_avx.hpp index c845ee2c..4e9cc3ba 100644 --- a/libsrc/core/simd_avx.hpp +++ b/libsrc/core/simd_avx.hpp @@ -172,7 +172,7 @@ namespace ngcore NETGEN_INLINE SIMD sqrt (SIMD a) { return _mm256_sqrt_pd(a.Data()); } NETGEN_INLINE SIMD floor (SIMD a) { return _mm256_floor_pd(a.Data()); } NETGEN_INLINE SIMD ceil (SIMD a) { return _mm256_ceil_pd(a.Data()); } - NETGEN_INLINE SIMD fabs (SIMD a) { return _mm256_max_pd(a.Data(), -a.Data()); } + NETGEN_INLINE SIMD fabs (SIMD a) { return _mm256_max_pd(a.Data(), (-a).Data()); } NETGEN_INLINE SIMD operator<= (SIMD a , SIMD b) { return _mm256_cmp_pd (a.Data(), b.Data(), _CMP_LE_OQ); } From 1f3aebcec06989540ce385f3451dbd09b817fae5 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Tue, 15 Dec 2020 09:37:56 +0100 Subject: [PATCH 284/384] Fix AVX-Operators for int64_t simd (use generic ones) --- libsrc/core/simd_avx.hpp | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/libsrc/core/simd_avx.hpp b/libsrc/core/simd_avx.hpp index 4e9cc3ba..91cb27ae 100644 --- a/libsrc/core/simd_avx.hpp +++ b/libsrc/core/simd_avx.hpp @@ -76,7 +76,9 @@ namespace ngcore SIMD (std::array a) : data{_mm256_set_epi64x(a[3],a[2],a[1],a[0])} {} - // SIMD (SIMD v0, SIMD v1) : SIMD(v0[0], v0[1], v1[0], v1[1]) { ; } + SIMD (SIMD v0, SIMD v1) + : data(_mm256_set_m128i(v0.Data(),v1.Data())) + {} SIMD (__m256i _data) { data = _data; } NETGEN_INLINE auto operator[] (int i) const { return ((int64_t*)(&data))[i]; } @@ -94,18 +96,7 @@ namespace ngcore #ifdef __AVX2__ NETGEN_INLINE SIMD operator+ (SIMD a, SIMD b) { return _mm256_add_epi64(a.Data(),b.Data()); } NETGEN_INLINE SIMD operator- (SIMD a, SIMD b) { return _mm256_sub_epi64(a.Data(),b.Data()); } -#else - NETGEN_INLINE SIMD operator+ (SIMD a, SIMD b) { - auto lo_sum = _mm256_extractf128_si256(a.Data(), 0) + _mm256_extractf128_si256(b.Data(), 0); - auto hi_sum = _mm256_extractf128_si256(a.Data(), 1) + _mm256_extractf128_si256(b.Data(), 1); - return _mm256_set_m128i(hi_sum,lo_sum); - } - NETGEN_INLINE SIMD operator- (SIMD a, SIMD b) { - auto lo_sub = _mm256_extractf128_si256(a.Data(), 0) - _mm256_extractf128_si256(b.Data(), 0); - auto hi_sub = _mm256_extractf128_si256(a.Data(), 1) - _mm256_extractf128_si256(b.Data(), 1); - return _mm256_set_m128i(hi_sub,lo_sub); - } -#endif +#endif // __AVX2__ template<> class SIMD From 1b55c51da5798f2c1e09f1500ffdfcb8b9973a79 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Tue, 15 Dec 2020 09:40:22 +0100 Subject: [PATCH 285/384] remove AlignedAlloc, use alignas --- libsrc/core/simd_avx.hpp | 4 ++-- libsrc/core/simd_avx512.hpp | 4 ++-- libsrc/core/simd_generic.hpp | 3 --- libsrc/core/simd_sse.hpp | 4 ++-- 4 files changed, 6 insertions(+), 9 deletions(-) diff --git a/libsrc/core/simd_avx.hpp b/libsrc/core/simd_avx.hpp index 91cb27ae..f089a0b2 100644 --- a/libsrc/core/simd_avx.hpp +++ b/libsrc/core/simd_avx.hpp @@ -61,7 +61,7 @@ namespace ngcore } template<> - class SIMD + class alignas(32) SIMD { __m256i data; @@ -99,7 +99,7 @@ namespace ngcore #endif // __AVX2__ template<> - class SIMD + class alignas(32) SIMD { __m256d data; diff --git a/libsrc/core/simd_avx512.hpp b/libsrc/core/simd_avx512.hpp index 1f06e826..e453b7e4 100644 --- a/libsrc/core/simd_avx512.hpp +++ b/libsrc/core/simd_avx512.hpp @@ -39,7 +39,7 @@ namespace ngcore }; template<> - class SIMD + class alignas(64) SIMD { __m512i data; @@ -76,7 +76,7 @@ namespace ngcore template<> - class SIMD : public AlignedAlloc> + class alignas(64) SIMD { __m512d data; public: diff --git a/libsrc/core/simd_generic.hpp b/libsrc/core/simd_generic.hpp index 4fc47c33..8ebd399a 100644 --- a/libsrc/core/simd_generic.hpp +++ b/libsrc/core/simd_generic.hpp @@ -624,9 +624,6 @@ namespace ngcore return ngcore::SIMD([a](int i)->double { return cosh(a[i]); } ); } - template - class AlignedAlloc { ; }; - template using MultiSIMD = SIMD; diff --git a/libsrc/core/simd_sse.hpp b/libsrc/core/simd_sse.hpp index 300ddc0b..b6f9c61e 100644 --- a/libsrc/core/simd_sse.hpp +++ b/libsrc/core/simd_sse.hpp @@ -39,7 +39,7 @@ namespace ngcore template<> - class SIMD + class alignas(16) SIMD { __m128i data; @@ -77,7 +77,7 @@ NETGEN_INLINE SIMD operator- (SIMD a, SIMD b) { template<> - class alignas(16) SIMD : public AlignedAlloc> + class alignas(16) SIMD { __m128d data; From dbe894fea373e7048a8ed8d7c3606a794fe57705 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Tue, 15 Dec 2020 10:12:30 +0100 Subject: [PATCH 286/384] Support for Apple M1 --- libsrc/core/ngcore_api.hpp | 8 ++++ libsrc/core/simd.hpp | 14 ++++--- libsrc/core/simd_generic.hpp | 78 +++++++++++++++++++++++++----------- libsrc/core/taskmanager.cpp | 8 +++- libsrc/core/utils.hpp | 23 +++++++++-- 5 files changed, 96 insertions(+), 35 deletions(-) diff --git a/libsrc/core/ngcore_api.hpp b/libsrc/core/ngcore_api.hpp index b6412157..330e7e33 100644 --- a/libsrc/core/ngcore_api.hpp +++ b/libsrc/core/ngcore_api.hpp @@ -67,6 +67,14 @@ #endif #endif +#if defined(__amd64__) || defined(_M_AMD64) +#define NETGEN_ARCH_AMD64 +#endif + +#if defined(__arm64__) || defined(_M_ARM64) +#define NETGEN_ARCH_ARM +#endif + #ifdef __MAC_OS_X_VERSION_MIN_REQUIRED #if __MAC_OS_X_VERSION_MIN_REQUIRED < 101400 // The c++ standard library on MacOS 10.13 and earlier has no aligned new operator, diff --git a/libsrc/core/simd.hpp b/libsrc/core/simd.hpp index 277dd851..0d69dec1 100644 --- a/libsrc/core/simd.hpp +++ b/libsrc/core/simd.hpp @@ -11,7 +11,7 @@ #include "simd_generic.hpp" -#if (defined(_M_AMD64) || defined(_M_X64) || defined(__SSE__)) +#ifdef NETGEN_ARCH_AMD64 #ifndef __SSE__ #define __SSE__ #endif @@ -28,6 +28,7 @@ namespace ngcore { +#ifdef NETGEN_ARCH_AMD64 NETGEN_INLINE auto HSum (SIMD v1, SIMD v2, SIMD v3, SIMD v4) { SIMD hsum1 = my_mm_hadd_pd (v1.Data(), v2.Data()); @@ -35,6 +36,12 @@ namespace ngcore return SIMD (hsum1, hsum2); } + NETGEN_INLINE auto GetMaskFromBits( unsigned int i ) + { + return SIMD::GetMaskFromBits(i); + } +#endif + NETGEN_INLINE void SIMDTranspose (SIMD a1, SIMD a2, SIMD a3, SIMD a4, SIMD & b1, SIMD & b2, SIMD & b3, SIMD & b4) @@ -59,11 +66,6 @@ namespace ngcore { return SIMD(HSum(s1), HSum(s2), HSum(s3), HSum(s4)); } - - NETGEN_INLINE auto GetMaskFromBits( unsigned int i ) - { - return SIMD::GetMaskFromBits(i); - } } #endif // NETGEN_CORE_SIMD_HPP diff --git a/libsrc/core/simd_generic.hpp b/libsrc/core/simd_generic.hpp index 8ebd399a..c83b5348 100644 --- a/libsrc/core/simd_generic.hpp +++ b/libsrc/core/simd_generic.hpp @@ -21,10 +21,10 @@ namespace ngcore return 8; #elif defined __AVX__ return 4; -#elif (defined(_M_AMD64) || defined(_M_X64) || defined(__SSE__)) +#elif defined NETGEN_ARCH_AMD64 return 2; #else - return 1; + return 2; #endif } @@ -104,8 +104,10 @@ namespace ngcore SIMD () {} SIMD (const SIMD &) = default; SIMD & operator= (const SIMD &) = default; - SIMD (int64_t val) { data = val; } - SIMD (std::array arr) + SIMD (int val) : data{val} {} + SIMD (int64_t val) : data{val} {} + SIMD (size_t val) : data(val) {} + explicit SIMD (std::array arr) : data{arr[0]} {} @@ -136,16 +138,18 @@ namespace ngcore SIMD (const SIMD &) = default; SIMD & operator= (const SIMD &) = default; + SIMD (int val) : lo{val}, high{val} { ; } SIMD (int64_t val) : lo{val}, high{val} { ; } + SIMD (size_t val) : lo{val}, high{val} { ; } SIMD (SIMD lo_, SIMD high_) : lo(lo_), high(high_) { ; } - SIMD( std::array arr ) + explicit SIMD( std::array arr ) : lo(detail::array_range(arr, 0)), high(detail::array_range(arr, N1)) {} template - SIMD(const T... vals) + explicit SIMD(const T... vals) : lo(detail::array_range(std::array{vals...}, 0)), high(detail::array_range(std::array{vals...}, N1)) { @@ -204,7 +208,7 @@ namespace ngcore SIMD (size_t val) { data = val; } SIMD (double const * p) { data = *p; } SIMD (double const * p, SIMD mask) { data = mask.Data() ? *p : 0.0; } - SIMD (std::array arr) + explicit SIMD (std::array arr) : data{arr[0]} {} @@ -253,19 +257,17 @@ namespace ngcore template >::value,int>::type = 0> SIMD (const T & func) { - for(auto i : IntRange(N1)) - lo[i] = func(i); - for(auto i : IntRange(N2)) - high[i] = func(N1+i); + double *p = (double*)this; + for(auto i : IntRange(N)) + p[i] = func(i); } template >::value,int>::type = 0> SIMD & operator= (const T & func) { - for(auto i : IntRange(N1)) - lo[i] = func(i); - for(auto i : IntRange(N2)) - high[i] = func(N1+i); + double *p = (double*)this; + for(auto i : IntRange(N)) + p[i] = func(i); return *this; } @@ -285,13 +287,13 @@ namespace ngcore : lo{p, mask.Lo()}, high{p+N1, mask.Hi()} { } - SIMD( std::array arr ) + explicit SIMD( std::array arr ) : lo(detail::array_range(arr, 0)), high(detail::array_range(arr, N1)) {} template - SIMD(const T... vals) + explicit SIMD(const T... vals) : lo(detail::array_range(std::array{vals...}, 0)), high(detail::array_range(std::array{vals...}, N1)) { @@ -312,7 +314,10 @@ namespace ngcore template> operator std::tuple () - { return std::tuple((*this)[0], (*this)[1]); } + { + double *p = (double*)this; + return std::tuple(p[0], p[1]); + } template> operator std::tuple () @@ -325,6 +330,7 @@ namespace ngcore if constexpr(I(); else return high.template Get(); } + auto Data() const { return *this; } }; @@ -359,42 +365,42 @@ namespace ngcore } template - NETGEN_INLINE SIMD operator< (SIMD & a, SIMD b) + NETGEN_INLINE SIMD operator< (SIMD a, SIMD b) { if constexpr(N==1) return a.Data() < b.Data(); else return { a.Lo() - NETGEN_INLINE SIMD operator<= (SIMD & a, SIMD b) + NETGEN_INLINE SIMD operator<= (SIMD a, SIMD b) { if constexpr(N==1) return a.Data() <= b.Data(); else return { a.Lo()<=b.Lo(), a.Hi()<=b.Hi() }; } template - NETGEN_INLINE SIMD operator> (SIMD & a, SIMD b) + NETGEN_INLINE SIMD operator> (SIMD a, SIMD b) { if constexpr(N==1) return a.Data() > b.Data(); else return { a.Lo()>b.Lo(), a.Hi()>b.Hi() }; } template - NETGEN_INLINE SIMD operator>= (SIMD & a, SIMD b) + NETGEN_INLINE SIMD operator>= (SIMD a, SIMD b) { if constexpr(N==1) return a.Data() >= b.Data(); else return { a.Lo()>=b.Lo(), a.Hi()>=b.Hi() }; } template - NETGEN_INLINE SIMD operator== (SIMD & a, SIMD b) + NETGEN_INLINE SIMD operator== (SIMD a, SIMD b) { if constexpr(N==1) return a.Data() == b.Data(); else return { a.Lo()==b.Lo(), a.Hi()==b.Hi() }; } template - NETGEN_INLINE SIMD operator!= (SIMD & a, SIMD b) + NETGEN_INLINE SIMD operator!= (SIMD a, SIMD b) { if constexpr(N==1) return a.Data() != b.Data(); else return { a.Lo()!=b.Lo(), a.Hi()!=b.Hi() }; @@ -547,6 +553,30 @@ namespace ngcore return ost; } + using std::sqrt; + template + NETGEN_INLINE ngcore::SIMD sqrt (ngcore::SIMD a) { + return ngcore::SIMD([a](int i)->double { return sqrt(a[i]); } ); + } + + using std::fabs; + template + NETGEN_INLINE ngcore::SIMD fabs (ngcore::SIMD a) { + return ngcore::SIMD([a](int i)->double { return fabs(a[i]); } ); + } + + using std::floor; + template + NETGEN_INLINE ngcore::SIMD floor (ngcore::SIMD a) { + return ngcore::SIMD([a](int i)->double { return floor(a[i]); } ); + } + + using std::ceil; + template + NETGEN_INLINE ngcore::SIMD ceil (ngcore::SIMD a) { + return ngcore::SIMD([a](int i)->double { return ceil(a[i]); } ); + } + using std::exp; template NETGEN_INLINE ngcore::SIMD exp (ngcore::SIMD a) { diff --git a/libsrc/core/taskmanager.cpp b/libsrc/core/taskmanager.cpp index a1049a1c..1d88b766 100644 --- a/libsrc/core/taskmanager.cpp +++ b/libsrc/core/taskmanager.cpp @@ -201,14 +201,14 @@ namespace ngcore ; } - static size_t calibrate_init_tsc = __rdtsc(); + static size_t calibrate_init_tsc = GetTimeCounter(); typedef std::chrono::system_clock TClock; static TClock::time_point calibrate_init_clock = TClock::now(); void TaskManager :: StopWorkers() { done = true; - double delta_tsc = __rdtsc()-calibrate_init_tsc; + double delta_tsc = GetTimeCounter()-calibrate_init_tsc; double delta_sec = std::chrono::duration(TClock::now()-calibrate_init_clock).count(); double frequ = (delta_sec != 0) ? delta_tsc/delta_sec : 2.7e9; @@ -421,7 +421,11 @@ namespace ngcore if (workers_on_node[j]) { while (complete[j] != jobnr) + { +#ifdef NETGEN_ARCH_AMD64 _mm_pause(); +#endif // NETGEN_ARCH_AMD64 + } } func = nullptr; diff --git a/libsrc/core/utils.hpp b/libsrc/core/utils.hpp index 81b0073f..ca015ae3 100644 --- a/libsrc/core/utils.hpp +++ b/libsrc/core/utils.hpp @@ -8,13 +8,19 @@ #include #include +#include "ngcore_api.hpp" // for NGCORE_API and CPU arch macros + +#if defined(__APPLE__) && defined(NETGEN_ARCH_ARM) +#include +#endif + +#ifdef NETGEN_ARCH_AMD64 #ifdef WIN32 #include // for __rdtsc() CPU time step counter #else #include // for __rdtsc() CPU time step counter #endif // WIN32 - -#include "ngcore_api.hpp" // for NGCORE_API +#endif // NETGEN_ARCH_AMD64 namespace ngcore { @@ -52,7 +58,16 @@ namespace ngcore inline TTimePoint GetTimeCounter() noexcept { - return TTimePoint(__rdtsc()); +#if defined(__APPLE__) && defined(NETGEN_ARCH_ARM) + return mach_absolute_time(); +#elif defined(NETGEN_ARCH_AMD64) + return __rdtsc(); +#elif defined(NETGEN_ARCH_ARM) + return __builtin_readcyclecounter(); +#else +#warning "Unsupported CPU architecture" + return 0; +#endif } template @@ -161,7 +176,9 @@ namespace ngcore while (!m.compare_exchange_weak(should, true)) { should = false; +#ifdef NETGEN_ARCH_AMD64 _mm_pause(); +#endif // NETGEN_ARCH_AMD64 } } void unlock() From bf855efd1bbef43be59174aeb4520aeefe4e3b30 Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Tue, 15 Dec 2020 15:07:48 +0100 Subject: [PATCH 287/384] fix usage of uninitialized value (valgrind) --- libsrc/csg/surface.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libsrc/csg/surface.cpp b/libsrc/csg/surface.cpp index cb6ab48b..6231897b 100644 --- a/libsrc/csg/surface.cpp +++ b/libsrc/csg/surface.cpp @@ -16,6 +16,7 @@ Surface :: Surface () strcpy (name, "noname"); bcprop = -1; bcname = "default"; + inverse = false; } Surface :: ~Surface() From 9c0dbec8c99288138a1dbaadc4461d0e6980e041 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Tue, 15 Dec 2020 15:31:17 +0100 Subject: [PATCH 288/384] Fix SIMD ctor and Unpack --- libsrc/core/simd_generic.hpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/libsrc/core/simd_generic.hpp b/libsrc/core/simd_generic.hpp index c83b5348..5846ad4c 100644 --- a/libsrc/core/simd_generic.hpp +++ b/libsrc/core/simd_generic.hpp @@ -76,7 +76,7 @@ namespace ngcore SIMD hi; public: - SIMD (int i) : lo(i), hi(i-N1) { ; } + SIMD (size_t i) : lo(i), hi(i>N1 ? i-N1 : 0) { ; } SIMD (SIMD lo_, SIMD hi_) : lo(lo_), hi(hi_) { ; } SIMD Lo() const { return lo; } SIMD Hi() const { return hi; } @@ -664,6 +664,11 @@ namespace ngcore { return std::make_tuple(SIMD{a.Data()}, SIMD{b.Data()} ); } + else if constexpr(N==2) + { + return std::make_tuple(SIMD{ a.Lo(), b.Lo() }, + SIMD{ a.Hi(), b.Hi() }); + } else { auto [a1,b1] = Unpack(a.Lo(), b.Lo()); From e68d8cea9b41947664b36803cd901651ded6f5f6 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Wed, 16 Dec 2020 10:57:20 +0100 Subject: [PATCH 289/384] workaround for missing intrinsic on GCC 7 --- libsrc/core/simd_avx.hpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/libsrc/core/simd_avx.hpp b/libsrc/core/simd_avx.hpp index f089a0b2..3f83dae6 100644 --- a/libsrc/core/simd_avx.hpp +++ b/libsrc/core/simd_avx.hpp @@ -11,6 +11,15 @@ namespace ngcore { + +#if defined(__GNUC__) && (__GNUC__ == 7) + // GCC7 does not have intrinsic _mm256_set_m128i, see + // https://stackoverflow.com/questions/32630458/setting-m256i-to-the-value-of-two-m128i-values + NETGEN_INLINE auto _mm256_set_m128i(__m128i v0, __m128i v1) { + return _mm256_insertf128_si256(_mm256_castsi128_si256(v1), (v0), 1); + } +#endif // defined(__GNUC__) && (__GNUC__ == 7) + #if defined(__AVX2__) NETGEN_INLINE __m256i my_mm256_cmpgt_epi64 (__m256i a, __m256i b) { From d97a9a65949f99075b7b56549b339ac2f6be5c8a Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Wed, 16 Dec 2020 17:20:18 +0100 Subject: [PATCH 290/384] Alignment for generic SIMD classes --- libsrc/core/simd_generic.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libsrc/core/simd_generic.hpp b/libsrc/core/simd_generic.hpp index 5846ad4c..36f44d85 100644 --- a/libsrc/core/simd_generic.hpp +++ b/libsrc/core/simd_generic.hpp @@ -67,7 +67,7 @@ namespace ngcore template - class SIMD + class alignas(GetDefaultSIMDSize()*sizeof(int64_t)) SIMD { static constexpr int N1 = std::min(GetDefaultSIMDSize(), N/2); static constexpr int N2 = N-N1; @@ -123,7 +123,7 @@ namespace ngcore }; template - class SIMD + class alignas(GetDefaultSIMDSize()*sizeof(int64_t)) SIMD { static constexpr int N1 = std::min(GetDefaultSIMDSize(), N/2); static constexpr int N2 = N-N1; @@ -240,7 +240,7 @@ namespace ngcore template - class SIMD + class alignas(GetDefaultSIMDSize()*sizeof(double)) SIMD { static constexpr int N1 = std::min(GetDefaultSIMDSize(), N/2); static constexpr int N2 = N-N1; From eb6ac164e7fe94af30348e6b3e447c775bac7230 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Wed, 16 Dec 2020 21:00:12 +0100 Subject: [PATCH 291/384] int64_t for masks --- libsrc/core/simd_avx.hpp | 2 +- libsrc/core/simd_generic.hpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libsrc/core/simd_avx.hpp b/libsrc/core/simd_avx.hpp index f089a0b2..09f5d7de 100644 --- a/libsrc/core/simd_avx.hpp +++ b/libsrc/core/simd_avx.hpp @@ -33,7 +33,7 @@ namespace ngcore { __m256i mask; public: - SIMD (size_t i) + SIMD (int64_t i) : mask(my_mm256_cmpgt_epi64(_mm256_set1_epi64x(i), _mm256_set_epi64x(3, 2, 1, 0))) { ; } diff --git a/libsrc/core/simd_generic.hpp b/libsrc/core/simd_generic.hpp index 36f44d85..849e0922 100644 --- a/libsrc/core/simd_generic.hpp +++ b/libsrc/core/simd_generic.hpp @@ -58,7 +58,7 @@ namespace ngcore { int64_t mask; public: - SIMD (size_t i) + SIMD (int64_t i) : mask(i > 0 ? -1 : 0) { ; } bool Data() const { return mask; } static constexpr int Size() { return 1; } @@ -76,7 +76,7 @@ namespace ngcore SIMD hi; public: - SIMD (size_t i) : lo(i), hi(i>N1 ? i-N1 : 0) { ; } + SIMD (int64_t i) : lo(i), hi(i-N1 ) { ; } SIMD (SIMD lo_, SIMD hi_) : lo(lo_), hi(hi_) { ; } SIMD Lo() const { return lo; } SIMD Hi() const { return hi; } From 65afc44dccb4b0c7d691aebc6fcb39412235a56b Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Thu, 17 Dec 2020 10:26:29 +0100 Subject: [PATCH 292/384] Handle USE_NATIVE_ARCH=ON correctly on Apple M1 --- CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2cb66344..7d7c284a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -474,6 +474,8 @@ if(USE_NATIVE_ARCH) else() message(STATUS "Build for generic CPU") endif() + elseif(APPLE AND CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") + # no flag necessary/available on Apple M1 else() target_compile_options(ngcore PUBLIC "-march=native") endif(WIN32) From 94ecf8de9246fa1b2cb0e521f1cf58cc5e90a5f5 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Fri, 18 Dec 2020 11:05:10 +0100 Subject: [PATCH 293/384] Fix private linking of Python The CMake export of Interface libraries also exports PRIVATE build settings, which leads to build errors with non-existing include paths and .lib files for binary distributions. Use the work-around mentioned here to circumvent this behavior: https://gitlab.kitware.com/cmake/cmake/-/issues/15415#note_849405 --- libsrc/core/CMakeLists.txt | 2 +- libsrc/csg/CMakeLists.txt | 4 ++-- libsrc/geom2d/CMakeLists.txt | 2 +- libsrc/meshing/CMakeLists.txt | 2 +- libsrc/occ/CMakeLists.txt | 2 +- libsrc/stlgeom/CMakeLists.txt | 4 ++-- libsrc/visualization/CMakeLists.txt | 2 +- ng/CMakeLists.txt | 4 ++-- 8 files changed, 11 insertions(+), 11 deletions(-) diff --git a/libsrc/core/CMakeLists.txt b/libsrc/core/CMakeLists.txt index 8c8506fe..383bab85 100644 --- a/libsrc/core/CMakeLists.txt +++ b/libsrc/core/CMakeLists.txt @@ -67,7 +67,7 @@ endif(USE_NUMA) install(TARGETS ngcore DESTINATION ${NG_INSTALL_DIR} COMPONENT netgen) -target_link_libraries(ngcore PUBLIC netgen_mpi PRIVATE netgen_python ${CMAKE_THREAD_LIBS_INIT}) +target_link_libraries(ngcore PUBLIC netgen_mpi PRIVATE "$" ${CMAKE_THREAD_LIBS_INIT}) install(FILES ngcore.hpp archive.hpp type_traits.hpp version.hpp ngcore_api.hpp logging.hpp exception.hpp symboltable.hpp paje_trace.hpp utils.hpp profiler.hpp mpi_wrapper.hpp diff --git a/libsrc/csg/CMakeLists.txt b/libsrc/csg/CMakeLists.txt index 7d196b5b..52514038 100644 --- a/libsrc/csg/CMakeLists.txt +++ b/libsrc/csg/CMakeLists.txt @@ -11,7 +11,7 @@ if(APPLE) set_target_properties( csg PROPERTIES SUFFIX ".so") endif(APPLE) -target_link_libraries(csg PUBLIC mesh PRIVATE netgen_python) +target_link_libraries(csg PUBLIC mesh PRIVATE "$") if(NOT WIN32) install( TARGETS csg ${NG_INSTALL_DIR}) endif(NOT WIN32) @@ -20,7 +20,7 @@ target_link_libraries(csg PUBLIC ngcore) if(USE_GUI) add_library(csgvis ${NG_LIB_TYPE} vscsg.cpp ) - target_link_libraries(csgvis PRIVATE netgen_python PUBLIC ngcore) + target_link_libraries(csgvis PRIVATE "$" PUBLIC ngcore) if(NOT WIN32) target_link_libraries(csgvis PUBLIC csg visual) if(APPLE) diff --git a/libsrc/geom2d/CMakeLists.txt b/libsrc/geom2d/CMakeLists.txt index 466cc5c4..eafec27c 100644 --- a/libsrc/geom2d/CMakeLists.txt +++ b/libsrc/geom2d/CMakeLists.txt @@ -4,7 +4,7 @@ if(APPLE) set_target_properties( geom2d PROPERTIES SUFFIX ".so") endif(APPLE) -target_link_libraries(geom2d PUBLIC ngcore mesh PRIVATE netgen_python) +target_link_libraries(geom2d PUBLIC ngcore mesh PRIVATE "$") if(NOT WIN32) install( TARGETS geom2d ${NG_INSTALL_DIR}) endif(NOT WIN32) diff --git a/libsrc/meshing/CMakeLists.txt b/libsrc/meshing/CMakeLists.txt index 9bf45a89..342dd1e0 100644 --- a/libsrc/meshing/CMakeLists.txt +++ b/libsrc/meshing/CMakeLists.txt @@ -23,7 +23,7 @@ endif(APPLE) target_link_libraries( mesh PUBLIC ngcore PRIVATE gprim la gen ) -target_link_libraries( mesh PRIVATE netgen_metis netgen_python ${ZLIB_LIBRARIES} ) +target_link_libraries( mesh PRIVATE netgen_metis "$" ${ZLIB_LIBRARIES} ) if(NOT WIN32) install( TARGETS mesh ${NG_INSTALL_DIR}) endif(NOT WIN32) diff --git a/libsrc/occ/CMakeLists.txt b/libsrc/occ/CMakeLists.txt index 7e7a2a65..9db6271b 100644 --- a/libsrc/occ/CMakeLists.txt +++ b/libsrc/occ/CMakeLists.txt @@ -9,7 +9,7 @@ if(USE_GUI) target_link_libraries(occvis PUBLIC ngcore) endif(USE_GUI) -target_link_libraries(occ PUBLIC ngcore PRIVATE netgen_python) +target_link_libraries(occ PUBLIC ngcore PRIVATE "$") if(NOT WIN32) target_link_libraries( occ PRIVATE ${OCC_LIBRARIES} ) diff --git a/libsrc/stlgeom/CMakeLists.txt b/libsrc/stlgeom/CMakeLists.txt index f8ce2fd3..81d4e836 100644 --- a/libsrc/stlgeom/CMakeLists.txt +++ b/libsrc/stlgeom/CMakeLists.txt @@ -8,11 +8,11 @@ if(NOT WIN32) install( TARGETS stl ${NG_INSTALL_DIR}) endif(NOT WIN32) -target_link_libraries( stl PUBLIC ngcore PRIVATE netgen_python ) +target_link_libraries( stl PUBLIC ngcore PRIVATE "$" ) if(USE_GUI) add_library(stlvis ${NG_LIB_TYPE} vsstl.cpp) - target_link_libraries(stlvis PRIVATE netgen_python PUBLIC ngcore) + target_link_libraries(stlvis PRIVATE "$" PUBLIC ngcore) if(NOT WIN32) target_link_libraries( stlvis PUBLIC stl ) install( TARGETS stlvis ${NG_INSTALL_DIR}) diff --git a/libsrc/visualization/CMakeLists.txt b/libsrc/visualization/CMakeLists.txt index a5604fb6..2a83c0e0 100644 --- a/libsrc/visualization/CMakeLists.txt +++ b/libsrc/visualization/CMakeLists.txt @@ -9,7 +9,7 @@ endif(USE_GUI) add_library(visual ${NG_LIB_TYPE} ${LIB_VISUAL_SOURCES}) -target_link_libraries( visual PUBLIC ngcore PRIVATE netgen_python ${MPI_CXX_LIBRARIES} ${OPENGL_LIBRARIES} ) +target_link_libraries( visual PUBLIC ngcore PRIVATE "$" ${MPI_CXX_LIBRARIES} ${OPENGL_LIBRARIES} ) install( TARGETS visual ${NG_INSTALL_DIR}) install(FILES diff --git a/ng/CMakeLists.txt b/ng/CMakeLists.txt index 82350afc..235ad46c 100644 --- a/ng/CMakeLists.txt +++ b/ng/CMakeLists.txt @@ -47,7 +47,7 @@ if(USE_GUI) if(WIN32) set_target_properties( gui PROPERTIES OUTPUT_NAME libgui ) endif(WIN32) - target_link_libraries( gui PRIVATE netgen_python ) + target_link_libraries( gui PRIVATE "$" ) endif(USE_GUI) @@ -61,7 +61,7 @@ if(USE_PYTHON) endif() add_library(ngpy SHARED netgenpy.cpp) - target_link_libraries( ngpy PUBLIC nglib PRIVATE netgen_python ) + target_link_libraries( ngpy PUBLIC nglib PRIVATE "$" ) if(APPLE) set_target_properties( ngpy PROPERTIES SUFFIX ".so") elseif(WIN32) From 1e8715dc34596b648c3d508f7f5c66316bd678a3 Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Fri, 18 Dec 2020 14:25:00 +0100 Subject: [PATCH 294/384] remove unused global mpi_comm --- ng/ngappinit.cpp | 4 ---- nglib/nglib.cpp | 5 ----- nglib/parallelfunc.cpp | 6 ------ 3 files changed, 15 deletions(-) diff --git a/ng/ngappinit.cpp b/ng/ngappinit.cpp index bc82e9dd..1e66f89d 100644 --- a/ng/ngappinit.cpp +++ b/ng/ngappinit.cpp @@ -11,10 +11,6 @@ #include extern void ParallelRun(); -namespace netgen -{ - MPI_Comm mesh_comm; -} #endif #include "../libsrc/interface/writeuser.hpp" diff --git a/nglib/nglib.cpp b/nglib/nglib.cpp index bcff69d0..7e039249 100644 --- a/nglib/nglib.cpp +++ b/nglib/nglib.cpp @@ -43,11 +43,6 @@ namespace netgen { #ifdef PARALLEL #include -namespace netgen -{ - // int id = 0, ntasks = 1; - MPI_Comm mesh_comm; -} #endif diff --git a/nglib/parallelfunc.cpp b/nglib/parallelfunc.cpp index 0e4398e2..920ed11b 100644 --- a/nglib/parallelfunc.cpp +++ b/nglib/parallelfunc.cpp @@ -33,12 +33,6 @@ namespace netgen { using namespace netgen; using netgen::RegisterUserFormats; -namespace netgen -{ - // int id, ntasks; - MPI_Comm mesh_comm; -} - void ParallelRun() { From 7bd454e3855bb2782821cb89df2fe7b993710057 Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Fri, 18 Dec 2020 15:58:51 +0100 Subject: [PATCH 295/384] use relative tolerance in identifypoints --- libsrc/csg/identify.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/libsrc/csg/identify.cpp b/libsrc/csg/identify.cpp index 935ed22f..e8dbb8fd 100644 --- a/libsrc/csg/identify.cpp +++ b/libsrc/csg/identify.cpp @@ -318,6 +318,10 @@ GetIdentifiedPoint (class Mesh & mesh, int pi) void PeriodicIdentification :: IdentifyPoints (class Mesh & mesh) { + Point3d p1, p2; + mesh.GetBox(p1, p2); + auto eps = 1e-6 * (p2-p1).Length(); + for (int i = 1; i <= mesh.GetNP(); i++) { Point<3> p = mesh.Point(i); @@ -327,7 +331,7 @@ void PeriodicIdentification :: IdentifyPoints (class Mesh & mesh) pp = trafo(pp); s2->Project (pp); for (int j = 1; j <= mesh.GetNP(); j++) - if (Dist2(mesh.Point(j), pp) < 1e-6) + if (Dist2(mesh.Point(j), pp) < eps) { mesh.GetIdentifications().Add (i, j, nr); /* From c1c10174beafd89e2b127a181ace0e27009b9de1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20Sch=C3=B6berl?= Date: Tue, 22 Dec 2020 09:37:09 +0100 Subject: [PATCH 296/384] FNMA asm-instruction --- libsrc/core/simd_avx.hpp | 36 ++++++++++++++++++++++++++++++++++++ libsrc/core/simd_generic.hpp | 8 ++++++++ 2 files changed, 44 insertions(+) diff --git a/libsrc/core/simd_avx.hpp b/libsrc/core/simd_avx.hpp index 0f3112a0..281b10c8 100644 --- a/libsrc/core/simd_avx.hpp +++ b/libsrc/core/simd_avx.hpp @@ -174,6 +174,42 @@ namespace ngcore NETGEN_INLINE SIMD ceil (SIMD a) { return _mm256_ceil_pd(a.Data()); } NETGEN_INLINE SIMD fabs (SIMD a) { return _mm256_max_pd(a.Data(), (-a).Data()); } + +#ifdef __FMA__ + NETGEN_INLINE SIMD FMA (SIMD a, SIMD b, SIMD c) + { + return _mm256_fmadd_pd (a.Data(), b.Data(), c.Data()); + } + NETGEN_INLINE SIMD FMA (const double & a, SIMD b, SIMD c) + { + return _mm256_fmadd_pd (_mm256_set1_pd(a), b.Data(), c.Data()); + } +#endif + +#if defined(__FMA__) && !defined(__AVX512F__) + // make sure to use the update-version of fma + // important in matrix kernels using 12 sum-registers, 3 a-values and updated b-value + // avx512 has enough registers, and gcc seems to use only the first 16 z-regs + NETGEN_INLINE void FMAasm (SIMD a, SIMD b, SIMD & sum) + { + asm ("vfmadd231pd %[a], %[b], %[sum]" + : [sum] "+x" (sum.Data()) + : [a] "x" (a.Data()), [b] "x" (b.Data()) + ); + } + + NETGEN_INLINE void FNMAasm (SIMD a, SIMD b, SIMD & sum) + { + asm ("vfnmadd231pd %[a], %[b], %[sum]" + : [sum] "+x" (sum.Data()) + : [a] "x" (a.Data()), [b] "x" (b.Data()) + ); + } +#endif + + + + NETGEN_INLINE SIMD operator<= (SIMD a , SIMD b) { return _mm256_cmp_pd (a.Data(), b.Data(), _CMP_LE_OQ); } NETGEN_INLINE SIMD operator< (SIMD a , SIMD b) diff --git a/libsrc/core/simd_generic.hpp b/libsrc/core/simd_generic.hpp index 849e0922..e479590d 100644 --- a/libsrc/core/simd_generic.hpp +++ b/libsrc/core/simd_generic.hpp @@ -527,6 +527,14 @@ namespace ngcore sum = FMA(a,b,sum); } + // update form of fms + template + void FNMAasm (SIMD a, SIMD b, SIMD & sum) + { + sum -= a*b; + } + + template T get(SIMD a) { return a[i]; } From ea7f6c1e945284bddb219291a2f437ff740a563f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20Sch=C3=B6berl?= Date: Tue, 22 Dec 2020 13:06:08 +0100 Subject: [PATCH 297/384] fnma intrinsic for avx512 --- libsrc/core/simd_avx.hpp | 8 ++++++++ libsrc/core/simd_avx512.hpp | 10 ++++++++++ libsrc/core/simd_generic.hpp | 13 ++++++++++--- 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/libsrc/core/simd_avx.hpp b/libsrc/core/simd_avx.hpp index 281b10c8..37a0bab8 100644 --- a/libsrc/core/simd_avx.hpp +++ b/libsrc/core/simd_avx.hpp @@ -184,6 +184,14 @@ namespace ngcore { return _mm256_fmadd_pd (_mm256_set1_pd(a), b.Data(), c.Data()); } + NETGEN_INLINE SIMD FNMA (SIMD a, SIMD b, SIMD c) + { + return _mm256_fnmadd_pd (a.Data(), b.Data(), c.Data()); + } + NETGEN_INLINE SIMD FNMA (const double & a, SIMD b, SIMD c) + { + return _mm256_fnmadd_pd (_mm256_set1_pd(a), b.Data(), c.Data()); + } #endif #if defined(__FMA__) && !defined(__AVX512F__) diff --git a/libsrc/core/simd_avx512.hpp b/libsrc/core/simd_avx512.hpp index e453b7e4..bf57f4e1 100644 --- a/libsrc/core/simd_avx512.hpp +++ b/libsrc/core/simd_avx512.hpp @@ -234,6 +234,16 @@ namespace ngcore { return _mm512_fmadd_pd (_mm512_set1_pd(a), b.Data(), c.Data()); } + + NETGEN_INLINE SIMD FNMA (SIMD a, SIMD b, SIMD c) + { + return _mm512_fnmadd_pd (a.Data(), b.Data(), c.Data()); + } + NETGEN_INLINE SIMD FNMA (const double & a, SIMD b, SIMD c) + { + return _mm512_fnmadd_pd (_mm512_set1_pd(a), b.Data(), c.Data()); + } + } #endif // NETGEN_CORE_SIMD_AVX512_HPP diff --git a/libsrc/core/simd_generic.hpp b/libsrc/core/simd_generic.hpp index e479590d..1ad4ea99 100644 --- a/libsrc/core/simd_generic.hpp +++ b/libsrc/core/simd_generic.hpp @@ -513,11 +513,17 @@ namespace ngcore } - template // a*b+c + template NETGEN_INLINE auto FMA(T1 a, T2 b, T3 c) { - return a*b+c; + return c+a*b; + } + + template + NETGEN_INLINE auto FNMA(T1 a, T2 b, T3 c) + { + return c-a*b; } // update form of fma @@ -531,7 +537,8 @@ namespace ngcore template void FNMAasm (SIMD a, SIMD b, SIMD & sum) { - sum -= a*b; + // sum -= a*b; + sum = FNMA(a,b,sum); } From e5d339ed99bd4b6cd213d4aecfba8a1af13f617d Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Fri, 8 Jan 2021 08:30:47 +0100 Subject: [PATCH 298/384] Print function value on double click --- libsrc/visualization/mvdraw.hpp | 2 + libsrc/visualization/vsmesh.cpp | 68 ++++++++++++++++++++--------- libsrc/visualization/vssolution.cpp | 29 ++++++++++-- 3 files changed, 75 insertions(+), 24 deletions(-) diff --git a/libsrc/visualization/mvdraw.hpp b/libsrc/visualization/mvdraw.hpp index cae7c792..a39e3acd 100644 --- a/libsrc/visualization/mvdraw.hpp +++ b/libsrc/visualization/mvdraw.hpp @@ -209,6 +209,8 @@ namespace netgen void BuildBadelList(); void BuildIdentifiedList(); void BuildDomainSurfList(); + + bool Unproject (int px, int py, Point<3> &p); }; DLL_HEADER extern VisualSceneMesh vsmesh; diff --git a/libsrc/visualization/vsmesh.cpp b/libsrc/visualization/vsmesh.cpp index 10a56905..ee74c64a 100644 --- a/libsrc/visualization/vsmesh.cpp +++ b/libsrc/visualization/vsmesh.cpp @@ -3128,9 +3128,7 @@ namespace netgen - - - void VisualSceneMesh :: MouseDblClick (int px, int py) + bool VisualSceneMesh :: Unproject (int px, int py, Point<3> &p) { shared_ptr mesh = GetMesh(); @@ -3150,20 +3148,59 @@ namespace netgen int hy = viewport[3]-py; GLfloat pz; + + if(lock) + { + lock->UnLock(); + delete lock; + lock = NULL; + } + + if(pz>=1.0) + return false; // cout << "x, y = " << px << ", " << hy << endl; glReadPixels (px, hy, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &pz); // cout << "pz = " << pz << endl; gluUnProject(px, hy, pz, transformationmat, projection, viewport, &result[0], &result[1], &result[2]); - if (pz < 1.0) - cout << "point : " << result[0] << ", " << result[1] << ", " << result[2] << endl; - + p = Point<3>{result[0], result[1], result[2]}; + return true; + } - if (user_me_handler && pz < 1.0) + + void VisualSceneMesh :: MouseDblClick (int px, int py) + { + Point<3> p; + bool found_point = Unproject(px, py, p); + + if(selelement!=-1) { - if (selelement != -1) - user_me_handler -> DblClick (selelement-1, result[0], result[1], result[2]); + const Element2d & sel = GetMesh()->SurfaceElement(selelement); + + cout << "select element " << selelement + << " on face " << sel.GetIndex() << endl; + cout << "Nodes: "; + for (int i = 1; i <= sel.GetNP(); i++) + cout << sel.PNum(i) << " "; + cout << endl; + + cout << "selected point " << selpoint + << ", pos = " << GetMesh()->Point (selpoint) + << endl; + + cout << "seledge = " << seledge << endl; + + } + + if(found_point) + { + cout << "point : " << p << endl; + if (user_me_handler) + { + if (selelement != -1) + user_me_handler -> DblClick (selelement-1, p[0], p[1], p[2]); + } } selecttimestamp = NextTimeStamp(); @@ -3401,6 +3438,7 @@ namespace netgen if (vispar.clipping.enable) { + glEnable(GL_CLIP_PLANE0); Vec<3> n(clipplane[0], clipplane[1], clipplane[2]); double len = Abs(n); double mu = -clipplane[3] / (len*len); @@ -3473,23 +3511,12 @@ namespace netgen { const Element2d & sel = mesh->SurfaceElement(minname); - - cout << "select element " << minname - << " on face " << sel.GetIndex() << endl; - cout << "Nodes: "; - for (i = 1; i <= sel.GetNP(); i++) - cout << sel.PNum(i) << " "; - cout << endl; - selelement = minname; selface = mesh->SurfaceElement(minname).GetIndex(); locpi = (locpi % sel.GetNP()) + 1; selpoint2 = selpoint; selpoint = sel.PNum(locpi); - cout << "selected point " << selpoint - << ", pos = " << mesh->Point (selpoint) - << endl; for (i = 1; i <= mesh->GetNSeg(); i++) { @@ -3498,7 +3525,6 @@ namespace netgen (seg[1] == selpoint && seg[0] == selpoint2) ) { seledge = seg.edgenr; - cout << "seledge = " << seledge << endl; } } } diff --git a/libsrc/visualization/vssolution.cpp b/libsrc/visualization/vssolution.cpp index 25decb88..f65c1e77 100644 --- a/libsrc/visualization/vssolution.cpp +++ b/libsrc/visualization/vssolution.cpp @@ -4754,9 +4754,32 @@ namespace netgen void VisualSceneSolution :: MouseDblClick (int px, int py) { - vsmesh.SetClippingPlane(); - // vsmesh.BuildFilledList(); - vsmesh.MouseDblClick(px,py); + Point<3> p; + bool found_point = vsmesh.Unproject(px, py, p); + if(!found_point) + return; + + + if(selelement>0) // found a surface element (possibliy behind clipping plane), check if drawn point really is in this element + { + double lami[3]; + lami[0] = lami[1] = lami[2] = 0.0; + // Check if unprojected Point is close to surface element (eps of 1e-3 due to z-Buffer accuracy) + if(GetMesh()->PointContainedIn2DElement(p, lami, selelement, false) && fabs(lami[2])<1e-3) + { + double val; + GetSurfValue(soldata[scalfunction], selelement-1, -1, 1.0-lami[0]-lami[1], lami[0], scalcomp, val); + cout << "surface function value: " << val << endl; + } + // otherwise assume that the unprojected point is on the clipping plane -> find 3d element containing it + else if(auto el3d = GetMesh()->GetElementOfPoint( p, lami )) + { + double val; + GetValue(soldata[scalfunction], el3d-1, lami[0], lami[1], lami[2], scalcomp, val); + cout << "clipping plane value: " << val << endl; + } + + } } From ccc686830afdf9ab8c5153d6d0c4e575f4107e02 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Tue, 12 Jan 2021 18:07:58 +0100 Subject: [PATCH 299/384] some more tests for csg2d --- tests/pytest/test_csg2d.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tests/pytest/test_csg2d.py b/tests/pytest/test_csg2d.py index 204e8ce1..596be0eb 100644 --- a/tests/pytest/test_csg2d.py +++ b/tests/pytest/test_csg2d.py @@ -3,6 +3,19 @@ import pytest import math from pytest import approx + +def check_area(geo, area): + if isinstance(geo, Solid2d): + g = CSG2d() + g.Add(geo) + geo = g + + m = geo.GenerateMesh() + ngs = pytest.importorskip("ngsolve") + mesh = ngs.Mesh(m) + mesh.Curve(5) + assert ngs.Integrate(1.0, mesh) == approx(area) + def test_two_circles(): c1 = Circle(center=(0,0), radius=1) c2 = c1.Rotate(45) @@ -82,6 +95,17 @@ def test_circle_plus_rect1(): mesh.Curve(5) assert ngs.Integrate(1.0, mesh) == approx(math.pi) +def test_circle_and_rect(): + c = Circle(center=(0,0),radius=1) + r = Rectangle((0,0),(1,1)) + + pi = math.pi + check_area(c-r, 3/4*pi) + check_area(c*r, 1/4*pi) + check_area(c+r, 3/4*pi+1) + check_area(r*c, 1/4*pi) + check_area(r+c, 3/4*pi+1) + if __name__ == "__main__": test_two_circles() From 96b9be9f9c8332a5e2c8da462ecc7c598ddcc8d6 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Tue, 12 Jan 2021 18:08:39 +0100 Subject: [PATCH 300/384] [WIP] Fix oracle function in csg2d --- libsrc/geom2d/csg2d.cpp | 94 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 84 insertions(+), 10 deletions(-) diff --git a/libsrc/geom2d/csg2d.cpp b/libsrc/geom2d/csg2d.cpp index 09f743b7..6a04f8f3 100644 --- a/libsrc/geom2d/csg2d.cpp +++ b/libsrc/geom2d/csg2d.cpp @@ -422,6 +422,64 @@ bool IsCloseToTrig( const array,3> & t, Point<2> r, double eps=1e-4 ) return IsInsideTrig( t, r ); } +bool IsLeft( const Spline & s, Point<2> p ) +{ + Point<2> a = s.StartPI(); + Point<2> b = s.TangentPoint(); + Point<2> c = s.EndPI(); + + // simple check by approximating spline with segment + bool is_left = Area(p, a, c) > 0.0; + + // not close to spline -> simple check valid + if(!IsCloseToTrig( {a, b, c} , p )) + return is_left; + + // p is control point -> simple check valid + auto bp = p-b; + if(bp.Length2() < EPSILON) + return is_left; + + double sab = Area(p, a, b); + double sbc = Area(p, b, c); + if(fabs(sab) same side of spline as control point, simple test gives correct result + // weight decreases -> opposite side of spline as control point, adding control point to test polygon gives correct result + double old_weight = s.GetWeight(); + auto s_tmp = s; + ComputeWeight( s_tmp, p ); + double new_weight = s_tmp.GetWeight(); + + if(new_weight>old_weight) + return is_left; + + double sabc = Area(a, b, c); + + if (sabc > 0) + { + // chain makes a left turn + if (sab > 0 && sbc > 0) + return true; + else + return false; + } + else + { + // chain makes a right turn (or is straight) + if (sab < 0 && sbc < 0) + return false; + else + return true; + } +} + + IntersectionType IntersectTrig( Point<2> p0, Point<2> p1, const array,3> & trig) { @@ -850,15 +908,26 @@ RelativePositionType oracle(bool prev, Vertex* P1, Vertex* P2, Vertex* P3) Point<2> p2 = *P2; Point<2> p3 = *P3; + double s1, s2, s3; + if(P1->spline) - p1 = P1->spline->TangentPoint(); + { + s1 = IsLeft(*P1->spline, q) ? 1 : -1; + p1 = P1->spline->TangentPoint(); + } + else + s1 = Area( q, p1, p2); + if(P2->spline) - p3 = P2->spline->TangentPoint(); + { + s2 = IsLeft(*P2->spline, q) ? 1 : -1; + p2 = P2->spline->TangentPoint(); + } + else + s2 = Area( q, p2, p3); // check relative position of Q with respect to chain (P1,P2,P3) - double s1 = Area( q, p1, p2); - double s2 = Area( q, p2, p3); - double s3 = Area( p1, p2, p3); + s3 = Area( p1, p2, p3); if (s3 > 0) { @@ -878,6 +947,14 @@ RelativePositionType oracle(bool prev, Vertex* P1, Vertex* P2, Vertex* P3) } } +RelativePositionType oracle(bool prev, Vertex* P2) +{ + Vertex* P1 = P2->prev; + Vertex* P3 = P2->next; + + return oracle(prev, P1, P2, P3); +} + void LabelIntersections(Solid2d & sp, Solid2d & sq, Solid2d & sr, bool UNION) { auto & PP = sp.polys; @@ -890,12 +967,9 @@ void LabelIntersections(Solid2d & sp, Solid2d & sq, Solid2d & sr, bool UNION) { // determine local configuration at this intersection vertex - Vertex* P_m = I->prev; - Vertex* P_p = I->next; - // check positions of Q- and Q+ relative to (P-, I, P+) - RelativePositionType Q_m_type = oracle(true, P_m, I, P_p); - RelativePositionType Q_p_type = oracle(false, P_m, I, P_p); + RelativePositionType Q_m_type = oracle(true, I); + RelativePositionType Q_p_type = oracle(false, I); // check non-overlapping cases if ((Q_m_type == LEFT && Q_p_type == RIGHT) || From 1502fd705e33928aff087366be10c6e87153dc51 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Tue, 12 Jan 2021 18:08:51 +0100 Subject: [PATCH 301/384] some debug messages --- libsrc/geom2d/csg2d.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/libsrc/geom2d/csg2d.cpp b/libsrc/geom2d/csg2d.cpp index 6a04f8f3..f489f6fe 100644 --- a/libsrc/geom2d/csg2d.cpp +++ b/libsrc/geom2d/csg2d.cpp @@ -150,6 +150,7 @@ IntersectionType ClassifyNonOverlappingIntersection( double alpha, double beta ) if (alpha_is_0 && beta_is_0) return (V_INTERSECTION); + cout << alpha << ',' << beta << ',' << alpha_is_0 << ',' << beta_is_0 << endl; return NO_INTERSECTION; } @@ -273,6 +274,7 @@ IntersectionType IntersectSplineSegment( const Spline & s, const Point<2> & r0, int dim = fabs(vr[0]) > fabs(vr[1]) ? 0 : 1; beta = 1.0/vr[dim] * (s.GetPoint(t)[dim] - r0[dim]); + cout << "intersect splinesegment " << alpha << ',' << beta << ',' << ClassifyNonOverlappingIntersection(alpha, beta) << endl; return ClassifyNonOverlappingIntersection(alpha, beta); } @@ -339,6 +341,7 @@ IntersectionType IntersectSplineSegment1( const Spline & s, const Point<2> & r0, alpha = valpha[choice]; beta = vbeta[choice]; + cout << "intersect splinesegment1 " << alpha << ',' << beta << ',' << vtype[choice] << endl; return vtype[choice]; } @@ -718,6 +721,7 @@ void AddIntersectionPoint(Edge edgeP, Edge edgeQ, IntersectionType i, double alp I_P = edgeP.v0->Insert(I, alpha); I_Q = edgeQ.v0->Insert(I, beta); I_P->Link(I_Q); + cout << "Add X Intersection " << *I_P << alpha << ',' << beta << endl; break; case X_OVERLAP: @@ -726,23 +730,28 @@ void AddIntersectionPoint(Edge edgeP, Edge edgeQ, IntersectionType i, double alp I_P = edgeP.v0->Insert(*Q1, alpha); I_P->Link( Q1); + cout << "Add X Overlap " << *I_P << alpha << ',' << beta << endl; break; case T_INTERSECTION_Q: case T_OVERLAP_Q: I_Q = edgeQ.v0->Insert(*P1, beta); P1->Link( I_Q); + cout << "Add T int/overlap Q " << *P1 << alpha << ',' << beta << endl; break; case T_INTERSECTION_P: case T_OVERLAP_P: I_P = edgeP.v0->Insert(*Q1, alpha); I_P->Link( Q1); + cout << "Add T int/overlap P " << *I_P << alpha << ',' << beta << endl; break; case V_INTERSECTION: case V_OVERLAP: P1->Link(Q1); + cout << "Add V int/overlap " << *P1 << alpha << ',' << beta << endl; + cout << *P1 << *P1->next << *Q1 << *Q1->next << endl; break; default: break; @@ -812,7 +821,7 @@ void ComputeIntersections(Edge edgeP , Loop & l2) // search for possible second intersection i = intersect(edgeP, edgeQ, alpha1, beta1); - // cout << "second intersection " << i << ',' << alpha1 << ',' << beta1 << ',' << alpha1-alpha << ',' << beta1-beta << endl; + cout << "second intersection " << i << ',' << alpha1 << ',' << beta1 << ',' << alpha1-alpha << ',' << beta1-beta << endl; if(i!=NO_INTERSECTION && alpha+EPSILON 0) { // chain makes a left turn @@ -1004,6 +1016,7 @@ void LabelIntersections(Solid2d & sp, Solid2d & sq, Solid2d & sr, bool UNION) if ( ( (Q_m_type == IS_P_m) && (Q_p_type == LEFT) ) || ( (Q_p_type == IS_P_m) && (Q_m_type == LEFT) ) ) I->label = ON_RIGHT; + cout << "label " << *I << " = " << I->label << endl; } // 2) classify intersection chains @@ -1015,6 +1028,7 @@ void LabelIntersections(Solid2d & sp, Solid2d & sq, Solid2d & sr, bool UNION) if (I->label == LEFT_ON || I->label == RIGHT_ON) { + cout << "intersection chain " << *I << endl; // remember status of the first chain vertex and vertex itself RelativePositionType x; From ba7fc0380084ae064280050d556ea9477822e181 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Wed, 13 Jan 2021 08:40:52 +0100 Subject: [PATCH 302/384] use pytest-check --- tests/dockerfile | 1 + tests/dockerfile_mpi | 2 +- tests/pytest/test_csg2d.py | 3 ++- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/dockerfile b/tests/dockerfile index 383189fd..7c20b027 100644 --- a/tests/dockerfile +++ b/tests/dockerfile @@ -2,4 +2,5 @@ FROM ubuntu:19.10 ENV DEBIAN_FRONTEND=noninteractive MAINTAINER Matthias Hochsteger RUN apt-get update && apt-get -y install python3 libpython3-dev libxmu-dev tk-dev tcl-dev cmake git g++ libglu1-mesa-dev ccache python3-pytest python3-numpy python3-tk clang-tidy python3-distutils clang libocct-data-exchange-dev libcgns-dev libhdf5-dev +RUN python3 -m pip install pytest-check ADD . /root/src/netgen diff --git a/tests/dockerfile_mpi b/tests/dockerfile_mpi index 220179a8..c90c0c28 100644 --- a/tests/dockerfile_mpi +++ b/tests/dockerfile_mpi @@ -2,5 +2,5 @@ FROM ubuntu:20.04 ENV DEBIAN_FRONTEND=noninteractive MAINTAINER Matthias Hochsteger RUN apt-get update && apt-get -y install python3 libpython3-dev python3-pip libxmu-dev tk-dev tcl-dev cmake git g++ libglu1-mesa-dev ccache python3-pytest python3-numpy python3-tk python3-mpi4py clang-tidy python3-distutils clang libopenmpi-dev openmpi-bin gfortran -RUN python3 -m pip install pytest-mpi +RUN python3 -m pip install pytest-mpi pytest-check ADD . /root/src/netgen diff --git a/tests/pytest/test_csg2d.py b/tests/pytest/test_csg2d.py index 596be0eb..b76e9998 100644 --- a/tests/pytest/test_csg2d.py +++ b/tests/pytest/test_csg2d.py @@ -2,6 +2,7 @@ from netgen.geom2d import * import pytest import math from pytest import approx +from pytest_check import check def check_area(geo, area): @@ -14,7 +15,7 @@ def check_area(geo, area): ngs = pytest.importorskip("ngsolve") mesh = ngs.Mesh(m) mesh.Curve(5) - assert ngs.Integrate(1.0, mesh) == approx(area) + with check: assert ngs.Integrate(1.0, mesh) == approx(area) def test_two_circles(): c1 = Circle(center=(0,0), radius=1) From 36aa8658b703d508daf97607e2bf73b4f69b91f1 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Wed, 13 Jan 2021 10:58:13 +0100 Subject: [PATCH 303/384] Print function names and surface/volume evaluation --- libsrc/visualization/vsmesh.cpp | 8 ++- libsrc/visualization/vssolution.cpp | 80 ++++++++++++++++++++++++----- 2 files changed, 73 insertions(+), 15 deletions(-) diff --git a/libsrc/visualization/vsmesh.cpp b/libsrc/visualization/vsmesh.cpp index ee74c64a..af7ea300 100644 --- a/libsrc/visualization/vsmesh.cpp +++ b/libsrc/visualization/vsmesh.cpp @@ -3156,10 +3156,14 @@ namespace netgen lock = NULL; } - if(pz>=1.0) - return false; // cout << "x, y = " << px << ", " << hy << endl; glReadPixels (px, hy, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &pz); + + if(pz>=1.0) + return false; + if(pz<=0.0) + return false; + // cout << "pz = " << pz << endl; gluUnProject(px, hy, pz, transformationmat, projection, viewport, &result[0], &result[1], &result[2]); diff --git a/libsrc/visualization/vssolution.cpp b/libsrc/visualization/vssolution.cpp index f65c1e77..c1c7555e 100644 --- a/libsrc/visualization/vssolution.cpp +++ b/libsrc/visualization/vssolution.cpp @@ -4759,24 +4759,78 @@ namespace netgen if(!found_point) return; + auto mesh = GetMesh(); + auto dim = mesh->GetDimension(); - if(selelement>0) // found a surface element (possibliy behind clipping plane), check if drawn point really is in this element + auto printScalValue = [](SolData & sol, int comp, double value) { - double lami[3]; - lami[0] = lami[1] = lami[2] = 0.0; - // Check if unprojected Point is close to surface element (eps of 1e-3 due to z-Buffer accuracy) - if(GetMesh()->PointContainedIn2DElement(p, lami, selelement, false) && fabs(lami[2])<1e-3) + if(sol.components>1) { - double val; - GetSurfValue(soldata[scalfunction], selelement-1, -1, 1.0-lami[0]-lami[1], lami[0], scalcomp, val); - cout << "surface function value: " << val << endl; + if(comp==0) + cout << "func(" << sol.name << ")"; + else + cout << sol.name << "["+ToString(comp)+"]"; } - // otherwise assume that the unprojected point is on the clipping plane -> find 3d element containing it - else if(auto el3d = GetMesh()->GetElementOfPoint( p, lami )) + else + cout << sol.name; + cout << " = " << value << endl; + }; + + if(selelement>0) // found a drawn point (clipping plane or surface element) + { + double lami[3] = {0.0, 0.0, 0.0}; + // Check if unprojected Point is close to surface element (eps of 1e-3 due to z-Buffer accuracy) + bool found_2del = false; + if(mesh->PointContainedIn2DElement(p, lami, selelement, false && fabs(lami[2])<1e-3)) { - double val; - GetValue(soldata[scalfunction], el3d-1, lami[0], lami[1], lami[2], scalcomp, val); - cout << "clipping plane value: " << val << endl; + // Found it, use coordinates of point projected to surface element + mesh->GetCurvedElements().CalcSurfaceTransformation({1.0-lami[0]-lami[1], lami[0]}, selelement-1, p); + found_2del = true; + } + cout << "Selected point " << p << " " << endl; + bool have_surf_scal_func = scalfunction!=-1 && soldata[scalfunction]->draw_surface && found_2del; + bool have_surf_vec_func = vecfunction!=-1 && soldata[vecfunction]->draw_surface && found_2del; + if(have_surf_scal_func || have_surf_vec_func) + { + cout << "Surface values:" << endl; + + if(have_surf_scal_func) + { + auto & sol = *soldata[scalfunction]; + double val; + GetSurfValue(&sol, selelement-1, -1, 1.0-lami[0]-lami[1], lami[0], scalcomp, val); + printScalValue(sol, scalcomp, val); + } + if(have_surf_vec_func) + { + auto & sol = *soldata[vecfunction]; + ArrayMem values(sol.components); + GetSurfValues(&sol, selelement-1, -1, 1.0-lami[0]-lami[1], lami[0], &values[0]); + cout << sol.name << " = " << values; + } + } + + bool have_vol_scal_func = scalfunction!=-1 && soldata[scalfunction]->draw_volume && !have_surf_scal_func; + bool have_vol_vec_func = vecfunction!=-1 && soldata[vecfunction]->draw_volume && !have_surf_vec_func; + // otherwise assume that the unprojected point is on the clipping plane -> find 3d element containing it + if(dim==3 && (have_vol_scal_func || have_vol_vec_func)) + if(auto el3d = mesh->GetElementOfPoint( p, lami )) + { + cout << "Volume values:" << endl; + if(have_vol_scal_func) + { + auto & sol = *soldata[scalfunction]; + double val; + GetValue(&sol, el3d-1, lami[0], lami[1], lami[2], scalcomp, val); + printScalValue(sol, scalcomp, val); + } + if(have_vol_vec_func) + { + auto & sol = *soldata[vecfunction]; + ArrayMem values(sol.components); + GetValues(&sol, el3d-1, lami[0], lami[1], lami[2], &values[0]); + cout << sol.name << " = " << values; + } } } From b7fab39876f0ecfb152f9b2a09c7bf787ec946e8 Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Wed, 13 Jan 2021 13:24:38 +0100 Subject: [PATCH 304/384] formatting of vector and complex output on click --- libsrc/visualization/vssolution.cpp | 67 +++++++++++++++++++++++++---- 1 file changed, 59 insertions(+), 8 deletions(-) diff --git a/libsrc/visualization/vssolution.cpp b/libsrc/visualization/vssolution.cpp index c1c7555e..8bd43342 100644 --- a/libsrc/visualization/vssolution.cpp +++ b/libsrc/visualization/vssolution.cpp @@ -4762,7 +4762,13 @@ namespace netgen auto mesh = GetMesh(); auto dim = mesh->GetDimension(); - auto printScalValue = [](SolData & sol, int comp, double value) + auto formatComplex = [](double real, double imag) + { + return ToString(real) + (imag < 0 ? "" : "+") + ToString(imag) + "j"; + }; + + auto printScalValue = [&formatComplex] + (SolData & sol, int comp, double value, double imag=0., bool iscomplex=false) { if(sol.components>1) { @@ -4773,7 +4779,7 @@ namespace netgen } else cout << sol.name; - cout << " = " << value << endl; + cout << " = " << (iscomplex ? formatComplex(value, imag) : ToString(value)) << endl; }; if(selelement>0) // found a drawn point (clipping plane or surface element) @@ -4798,15 +4804,37 @@ namespace netgen { auto & sol = *soldata[scalfunction]; double val; - GetSurfValue(&sol, selelement-1, -1, 1.0-lami[0]-lami[1], lami[0], scalcomp, val); - printScalValue(sol, scalcomp, val); + double imag = 0; + int rcomponent = scalcomp; + int comp = scalcomp; + if(sol.iscomplex && rcomponent != 0) + { + rcomponent = 2 * ((rcomponent-1)/2) + 1; + GetSurfValue(&sol, selelement-1, -1, 1.0-lami[0]-lami[1], lami[0], rcomponent+1, imag); + comp = (scalcomp-1)/2 + 1; + } + GetSurfValue(&sol, selelement-1, -1, 1.0-lami[0]-lami[1], lami[0], rcomponent, val); + printScalValue(sol, comp, val, imag, sol.iscomplex && comp > 0); } if(have_surf_vec_func) { auto & sol = *soldata[vecfunction]; ArrayMem values(sol.components); GetSurfValues(&sol, selelement-1, -1, 1.0-lami[0]-lami[1], lami[0], &values[0]); - cout << sol.name << " = " << values; + if(sol.iscomplex) + { + cout << sol.name << " = ( " << formatComplex(values[0], values[1]); + for(int i = 2; i < values.Size(); i+=2) + cout << ", " << formatComplex(values[i], values[i+1]); + cout << " )" << endl; + } + else + { + cout << sol.name << " = ( " << values[0]; + for(int i = 1; i < values.Size(); i++) + cout << ", " << values[i]; + cout << " )" << endl; + } } } @@ -4821,15 +4849,38 @@ namespace netgen { auto & sol = *soldata[scalfunction]; double val; - GetValue(&sol, el3d-1, lami[0], lami[1], lami[2], scalcomp, val); - printScalValue(sol, scalcomp, val); + double imag = 0; + int rcomponent = scalcomp; + int comp = scalcomp; + if(sol.iscomplex && rcomponent != 0) + { + rcomponent = 2 * ((rcomponent-1)/2) + 1; + GetValue(&sol, el3d-1, lami[0], lami[1], lami[2], rcomponent+1, + imag); + comp = (scalcomp-1)/2 + 1; + } + GetValue(&sol, el3d-1, lami[0], lami[1], lami[2], rcomponent, val); + printScalValue(sol, comp, val, imag, sol.iscomplex && comp > 0); } if(have_vol_vec_func) { auto & sol = *soldata[vecfunction]; ArrayMem values(sol.components); GetValues(&sol, el3d-1, lami[0], lami[1], lami[2], &values[0]); - cout << sol.name << " = " << values; + if(sol.iscomplex) + { + cout << sol.name << " = ( " << formatComplex(values[0], values[1]); + for(int i = 2; i < values.Size(); i+=2) + cout << ", " << formatComplex(values[i], values[i+1]); + cout << " )" << endl; + } + else + { + cout << sol.name << " = ( " << values[0]; + for(int i = 1; i < values.Size(); i++) + cout << ", " << values[i]; + cout << " )" << endl; + } } } From e745d16c6d03c52d8df6f24253e5e9e63bda8a74 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Wed, 13 Jan 2021 16:48:16 +0100 Subject: [PATCH 305/384] manually cut view vector with clipping plane (more accurate, also working when visualizing clipping plane vectors) --- libsrc/visualization/vssolution.cpp | 213 ++++++++++++++++------------ 1 file changed, 121 insertions(+), 92 deletions(-) diff --git a/libsrc/visualization/vssolution.cpp b/libsrc/visualization/vssolution.cpp index 8bd43342..0af2f5ad 100644 --- a/libsrc/visualization/vssolution.cpp +++ b/libsrc/visualization/vssolution.cpp @@ -4754,11 +4754,6 @@ namespace netgen void VisualSceneSolution :: MouseDblClick (int px, int py) { - Point<3> p; - bool found_point = vsmesh.Unproject(px, py, p); - if(!found_point) - return; - auto mesh = GetMesh(); auto dim = mesh->GetDimension(); @@ -4782,108 +4777,142 @@ namespace netgen cout << " = " << (iscomplex ? formatComplex(value, imag) : ToString(value)) << endl; }; - if(selelement>0) // found a drawn point (clipping plane or surface element) + auto printVecValue = [&formatComplex] + (SolData & sol, FlatArray values) { - double lami[3] = {0.0, 0.0, 0.0}; - // Check if unprojected Point is close to surface element (eps of 1e-3 due to z-Buffer accuracy) - bool found_2del = false; - if(mesh->PointContainedIn2DElement(p, lami, selelement, false && fabs(lami[2])<1e-3)) + if(sol.iscomplex) { - // Found it, use coordinates of point projected to surface element - mesh->GetCurvedElements().CalcSurfaceTransformation({1.0-lami[0]-lami[1], lami[0]}, selelement-1, p); - found_2del = true; + cout << sol.name << " = ( " << formatComplex(values[0], values[1]); + for(int i = 2; i < values.Size(); i+=2) + cout << ", " << formatComplex(values[i], values[i+1]); + cout << " )" << endl; } - cout << "Selected point " << p << " " << endl; - bool have_surf_scal_func = scalfunction!=-1 && soldata[scalfunction]->draw_surface && found_2del; - bool have_surf_vec_func = vecfunction!=-1 && soldata[vecfunction]->draw_surface && found_2del; - if(have_surf_scal_func || have_surf_vec_func) + else { - cout << "Surface values:" << endl; + cout << sol.name << " = ( " << values[0]; + for(int i = 1; i < values.Size(); i++) + cout << ", " << values[i]; + cout << " )" << endl; + } + }; - if(have_surf_scal_func) + // Check if clipping plane is drawn at current mouse cursor position + if(dim==3 && clipsolution && vispar.clipping.enable) + { + GLint viewport[4]; + GLdouble projection[16]; + glGetDoublev(GL_PROJECTION_MATRIX, &projection[0]); + + glGetIntegerv(GL_VIEWPORT, &viewport[0]); + + int hy = viewport[3]-py; + + // manually intersect the view vector with the clipping plane (also working if clipping vectors are shown) + Point<3> p_clipping_plane; + gluUnProject(px, hy, 1.0, transformationmat, projection, viewport, + &p_clipping_plane[0], &p_clipping_plane[1], &p_clipping_plane[2]); + + Point<3> eye; + gluUnProject( (viewport[2]-viewport[0])/2 , (viewport[3]-viewport[1])/2, + 0.0, transformationmat, projection, viewport, &eye[0], &eye[1], &eye[2]); + + Vec<3> n{vispar.clipping.normal}; + n.Normalize(); + Vec<3> view = p_clipping_plane-eye; + + // check if we look at the clipping plane from the right direction + if(n*view > 1e-8) + { + double lam = vispar.clipping.dist - Vec<3>{eye}*n; + lam /= n*view; + p_clipping_plane = eye + lam*view; + + double lami[3]; + if(auto el3d = mesh->GetElementOfPoint( p_clipping_plane, lami )) { - auto & sol = *soldata[scalfunction]; - double val; - double imag = 0; - int rcomponent = scalcomp; - int comp = scalcomp; - if(sol.iscomplex && rcomponent != 0) + cout << endl << "Selected point " << p_clipping_plane << " on clipping plane" << endl; + + bool have_scal_func = scalfunction!=-1 && soldata[scalfunction]->draw_volume; + bool have_vec_func = vecfunction!=-1 && soldata[vecfunction]->draw_volume; + + if(have_scal_func) { - rcomponent = 2 * ((rcomponent-1)/2) + 1; - GetSurfValue(&sol, selelement-1, -1, 1.0-lami[0]-lami[1], lami[0], rcomponent+1, imag); - comp = (scalcomp-1)/2 + 1; + auto & sol = *soldata[scalfunction]; + double val; + double imag = 0; + int rcomponent = scalcomp; + int comp = scalcomp; + if(sol.iscomplex && rcomponent != 0) + { + rcomponent = 2 * ((rcomponent-1)/2) + 1; + GetValue(&sol, el3d-1, lami[0], lami[1], lami[2], rcomponent+1, + imag); + comp = (scalcomp-1)/2 + 1; + } + GetValue(&sol, el3d-1, lami[0], lami[1], lami[2], rcomponent, val); + printScalValue(sol, comp, val, imag, sol.iscomplex && comp > 0); } - GetSurfValue(&sol, selelement-1, -1, 1.0-lami[0]-lami[1], lami[0], rcomponent, val); - printScalValue(sol, comp, val, imag, sol.iscomplex && comp > 0); - } - if(have_surf_vec_func) - { - auto & sol = *soldata[vecfunction]; - ArrayMem values(sol.components); - GetSurfValues(&sol, selelement-1, -1, 1.0-lami[0]-lami[1], lami[0], &values[0]); - if(sol.iscomplex) + if(vecfunction!=-1 && soldata[vecfunction]->draw_volume) { - cout << sol.name << " = ( " << formatComplex(values[0], values[1]); - for(int i = 2; i < values.Size(); i+=2) - cout << ", " << formatComplex(values[i], values[i+1]); - cout << " )" << endl; - } - else - { - cout << sol.name << " = ( " << values[0]; - for(int i = 1; i < values.Size(); i++) - cout << ", " << values[i]; - cout << " )" << endl; + auto & sol = *soldata[vecfunction]; + ArrayMem values(sol.components); + GetValues(&sol, el3d-1, lami[0], lami[1], lami[2], &values[0]); + printVecValue(sol, values); } + return; } } + } - bool have_vol_scal_func = scalfunction!=-1 && soldata[scalfunction]->draw_volume && !have_surf_scal_func; - bool have_vol_vec_func = vecfunction!=-1 && soldata[vecfunction]->draw_volume && !have_surf_vec_func; - // otherwise assume that the unprojected point is on the clipping plane -> find 3d element containing it - if(dim==3 && (have_vol_scal_func || have_vol_vec_func)) - if(auto el3d = mesh->GetElementOfPoint( p, lami )) + // no point on clipping plane found -> continue searching for surface element + + Point<3> p; + bool found_point = vsmesh.Unproject(px, py, p); + if(!found_point) + return; + + if(selelement==0) + return; + + double lami[3] = {0.0, 0.0, 0.0}; + // Check if unprojected Point is close to surface element (eps of 1e-3 due to z-Buffer accuracy) + bool found_2del = false; + if(mesh->PointContainedIn2DElement(p, lami, selelement, false && fabs(lami[2])<1e-3)) + { + // Found it, use coordinates of point projected to surface element + mesh->GetCurvedElements().CalcSurfaceTransformation({1.0-lami[0]-lami[1], lami[0]}, selelement-1, p); + found_2del = true; + } + cout << endl << "Selected point " << p << " on surface" << endl; + + if(!found_2del) + return; + + bool have_scal_func = scalfunction!=-1 && soldata[scalfunction]->draw_surface; + bool have_vec_func = vecfunction!=-1 && soldata[vecfunction]->draw_surface; + + if(have_scal_func) + { + auto & sol = *soldata[scalfunction]; + double val; + double imag = 0; + int rcomponent = scalcomp; + int comp = scalcomp; + if(sol.iscomplex && rcomponent != 0) { - cout << "Volume values:" << endl; - if(have_vol_scal_func) - { - auto & sol = *soldata[scalfunction]; - double val; - double imag = 0; - int rcomponent = scalcomp; - int comp = scalcomp; - if(sol.iscomplex && rcomponent != 0) - { - rcomponent = 2 * ((rcomponent-1)/2) + 1; - GetValue(&sol, el3d-1, lami[0], lami[1], lami[2], rcomponent+1, - imag); - comp = (scalcomp-1)/2 + 1; - } - GetValue(&sol, el3d-1, lami[0], lami[1], lami[2], rcomponent, val); - printScalValue(sol, comp, val, imag, sol.iscomplex && comp > 0); - } - if(have_vol_vec_func) - { - auto & sol = *soldata[vecfunction]; - ArrayMem values(sol.components); - GetValues(&sol, el3d-1, lami[0], lami[1], lami[2], &values[0]); - if(sol.iscomplex) - { - cout << sol.name << " = ( " << formatComplex(values[0], values[1]); - for(int i = 2; i < values.Size(); i+=2) - cout << ", " << formatComplex(values[i], values[i+1]); - cout << " )" << endl; - } - else - { - cout << sol.name << " = ( " << values[0]; - for(int i = 1; i < values.Size(); i++) - cout << ", " << values[i]; - cout << " )" << endl; - } - } + rcomponent = 2 * ((rcomponent-1)/2) + 1; + GetSurfValue(&sol, selelement-1, -1, 1.0-lami[0]-lami[1], lami[0], rcomponent+1, imag); + comp = (scalcomp-1)/2 + 1; } - + GetSurfValue(&sol, selelement-1, -1, 1.0-lami[0]-lami[1], lami[0], rcomponent, val); + printScalValue(sol, comp, val, imag, sol.iscomplex && comp > 0); + } + if(have_vec_func) + { + auto & sol = *soldata[vecfunction]; + ArrayMem values(sol.components); + GetSurfValues(&sol, selelement-1, -1, 1.0-lami[0]-lami[1], lami[0], &values[0]); + printVecValue(sol, values); } } From 12ebcd0d68cd010da6bf9f30a078f70f06b66d92 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Thu, 14 Jan 2021 17:11:46 +0100 Subject: [PATCH 306/384] Fix oracle function and intersection bug in csg2d --- libsrc/geom2d/csg2d.cpp | 205 ++++++++++++++++++++++++++-------------- 1 file changed, 134 insertions(+), 71 deletions(-) diff --git a/libsrc/geom2d/csg2d.cpp b/libsrc/geom2d/csg2d.cpp index f489f6fe..99a45b65 100644 --- a/libsrc/geom2d/csg2d.cpp +++ b/libsrc/geom2d/csg2d.cpp @@ -150,7 +150,6 @@ IntersectionType ClassifyNonOverlappingIntersection( double alpha, double beta ) if (alpha_is_0 && beta_is_0) return (V_INTERSECTION); - cout << alpha << ',' << beta << ',' << alpha_is_0 << ',' << beta_is_0 << endl; return NO_INTERSECTION; } @@ -274,7 +273,6 @@ IntersectionType IntersectSplineSegment( const Spline & s, const Point<2> & r0, int dim = fabs(vr[0]) > fabs(vr[1]) ? 0 : 1; beta = 1.0/vr[dim] * (s.GetPoint(t)[dim] - r0[dim]); - cout << "intersect splinesegment " << alpha << ',' << beta << ',' << ClassifyNonOverlappingIntersection(alpha, beta) << endl; return ClassifyNonOverlappingIntersection(alpha, beta); } @@ -295,8 +293,11 @@ IntersectionType IntersectSplineSegment1( const Spline & s, const Point<2> & r0, double c_ = a0; double det = b_*b_ - 4*a_*c_; - if(det<0.0) - return NO_INTERSECTION; + if(det<-EPSILON) + return NO_INTERSECTION; + + if(det & r0, alpha = valpha[choice]; beta = vbeta[choice]; - cout << "intersect splinesegment1 " << alpha << ',' << beta << ',' << vtype[choice] << endl; return vtype[choice]; } @@ -721,7 +721,6 @@ void AddIntersectionPoint(Edge edgeP, Edge edgeQ, IntersectionType i, double alp I_P = edgeP.v0->Insert(I, alpha); I_Q = edgeQ.v0->Insert(I, beta); I_P->Link(I_Q); - cout << "Add X Intersection " << *I_P << alpha << ',' << beta << endl; break; case X_OVERLAP: @@ -730,28 +729,23 @@ void AddIntersectionPoint(Edge edgeP, Edge edgeQ, IntersectionType i, double alp I_P = edgeP.v0->Insert(*Q1, alpha); I_P->Link( Q1); - cout << "Add X Overlap " << *I_P << alpha << ',' << beta << endl; break; case T_INTERSECTION_Q: case T_OVERLAP_Q: I_Q = edgeQ.v0->Insert(*P1, beta); P1->Link( I_Q); - cout << "Add T int/overlap Q " << *P1 << alpha << ',' << beta << endl; break; case T_INTERSECTION_P: case T_OVERLAP_P: I_P = edgeP.v0->Insert(*Q1, alpha); I_P->Link( Q1); - cout << "Add T int/overlap P " << *I_P << alpha << ',' << beta << endl; break; case V_INTERSECTION: case V_OVERLAP: P1->Link(Q1); - cout << "Add V int/overlap " << *P1 << alpha << ',' << beta << endl; - cout << *P1 << *P1->next << *Q1 << *Q1->next << endl; break; default: break; @@ -810,8 +804,8 @@ void ComputeIntersections(Edge edgeP , Loop & l2) { for (Edge edgeQ : l2.Edges(SOURCE)) { - double alpha = 0.0; - double beta = 0.0; + double alpha = -1; + double beta = -1; IntersectionType i = intersect(edgeP, edgeQ, alpha, beta); AddIntersectionPoint(edgeP, edgeQ, i, alpha, beta); if(i==X_INTERSECTION && (edgeP.v0->spline || edgeQ.v0->spline)) @@ -821,7 +815,6 @@ void ComputeIntersections(Edge edgeP , Loop & l2) // search for possible second intersection i = intersect(edgeP, edgeQ, alpha1, beta1); - cout << "second intersection " << i << ',' << alpha1 << ',' << beta1 << ',' << alpha1-alpha << ',' << beta1-beta << endl; if(i!=NO_INTERSECTION && alpha+EPSILON q; - if(prev) - { - Q = P2->neighbour->prev; - q = *Q; - if(Q->spline) - q = Q->spline->TangentPoint(); - } - else - { - Q = P2->neighbour->next; - q = *Q; - if(P2->neighbour->spline) - q = P2->neighbour->spline->TangentPoint(); - } - - // is Q linked to P1 ? - if ( P1->is_intersection && (P1->neighbour == Q) ) - return(IS_P_m); - - // is Q linked to P2 ? - if ( P3->is_intersection && (P3->neighbour == Q) ) - return(IS_P_p); - - Point<2> p1 = *P1; - Point<2> p2 = *P2; - Point<2> p3 = *P3; - - double s1, s2, s3; - - if(P1->spline) - { - s1 = IsLeft(*P1->spline, q) ? 1 : -1; - p1 = P1->spline->TangentPoint(); - } - else - s1 = Area( q, p1, p2); - - if(P2->spline) - { - s2 = IsLeft(*P2->spline, q) ? 1 : -1; - p2 = P2->spline->TangentPoint(); - } - else - s2 = Area( q, p2, p3); - - // check relative position of Q with respect to chain (P1,P2,P3) - s3 = Area( p1, p2, p3); - - cout << "Points for oracle " << q << p1 << p2 << p3 << endl; - cout << "areas " << s1 << ',' << s2 << ',' << s3 << endl; - if (s3 > 0) { // chain makes a left turn @@ -959,14 +899,139 @@ RelativePositionType oracle(bool prev, Vertex* P1, Vertex* P2, Vertex* P3) } } +// no splines involved here +// decides if Point q is left or right of chain (p1,p2,p3) +RelativePositionType oracle_simple(Point<2> q, Point<2> p1, Point<2> p2, Point<2> p3) +{ + double s1 = Area( q, p1, p2); + double s2 = Area( q, p2, p3); + double s3 = Area( p1, p2, p3); + + // check relative position of q with respect to chain (p1,p2,p3) + return oracle_decide(s1, s2, s3); +} + +// (p1,p2) or (p2,p3) is a spline segment, compare with tangent (p1t,p2) instead of Segment (p1,p2) +// BUT take care if tangent is collinear with (q,p2) (then use the segment (p1,p2) again) +RelativePositionType oracle_spline_p(Point<2> q, Point<2> p1, Point<2> p1t, Point<2> p2, Point<2> p3, Point<2> p3t) +{ + double s1 = Area( q, p1t, p2); + double s2 = Area( q, p2, p3t); + + if(fabs(s1) < EPSILON) + { + p1t = p1; + s1 = Area( q, p1t, p2 ); + } + + if(fabs(s2) < EPSILON) + { + p3t = p3; + s2 = Area( q, p2, p3t ); + } + + double s3 = Area( p1t, p2, p3t); + + return oracle_decide(s1, s2, s3); +} + +// (q,p2) is a spline segment, compare with tangent (qt,p2) instead of Segment (q,p2) +// BUT take care if tangent at p2 is collinear with eiter (p1,p2) or (p2,p3) (then use the segment (q,p2) again) +RelativePositionType oracle_spline_q(Point<2> q, Point<2> qt, Point<2> p1, Point<2> p2, Point<2> p3) +{ + double s1 = Area( qt, p1, p2); + double s2 = Area( qt, p2, p3); + double s3 = Area( p1, p2, p3); + + if(fabs(s1) < EPSILON) + s1 = Area( q, p1, p2 ); + + if(fabs(s2) < EPSILON) + s2 = Area( q, p2, p3 ); + + return oracle_decide(s1, s2, s3); +} + +// splines at (Q,P2) and either (P1,P2) or (P2,P3) +// first use tangents to decide local orientation +// if tangents of two splines match, use IsLeft(spline, other end point) +// if tangent of spline and segment match, use simple methond (just end points) +RelativePositionType oracle_spline(bool prev, Vertex *Q, Vertex *P1, Vertex *P2, Vertex *P3) +{ + Point<2> p1t = *P1; + Point<2> p3t = *P3; + + auto sq = prev ? Q->spline : Q->prev->spline; + auto qt = sq->TangentPoint(); + if(P1->spline) p1t = P1->spline->TangentPoint(); + if(P2->spline) p3t = P2->spline->TangentPoint(); + + // Check using tangent directions first + double s1 = Area( qt, p1t, *P2 ); + double s2 = Area( qt, *P2 , p3t); + double s3 = Area( p1t, *P2, p3t); + + // tangents are facing in same direction + if(fabs(s1) < EPSILON) + { + if(P1->spline) + s1 = IsLeft(*P1->spline, *Q) ? 1 : -1; + else + s1 = Area( *Q, *P1, *P2 ); + } + + // tangents are facing in same direction + if(fabs(s2) < EPSILON) + { + if(P2->spline) + s2 = IsLeft(*P2->spline, *Q) ? 1 : -1; + else + s2 = Area( *Q, *P2, *P3 ); + } + + return oracle_decide(s1, s2, s3); +} + + RelativePositionType oracle(bool prev, Vertex* P2) { + auto Q = prev ? P2->neighbour->prev : P2->neighbour->next; + auto sq = prev ? Q->spline : Q->prev->spline; Vertex* P1 = P2->prev; Vertex* P3 = P2->next; - return oracle(prev, P1, P2, P3); + // is Q linked to P1 ? + if ( P1->is_intersection && (P1->neighbour == Q) ) + return(IS_P_m); + + // is Q linked to P2 ? + if ( P3->is_intersection && (P3->neighbour == Q) ) + return(IS_P_p); + + // no splines -> simple variant + if(!P1->spline && !P2->spline && !Q->spline) + return oracle_simple(*Q, *P1, *P2, *P3); + + Point<2> qt=*Q, p1t=*P1, p3t=*P3; + + // splines -> also consider tangent points + if( sq) qt = Q->spline->TangentPoint(); + if(P1->spline) p1t = P1->spline->TangentPoint(); + if(P2->spline) p3t = P2->spline->TangentPoint(); + + // only spline at Q + if(!P1->spline && !P2->spline && Q->spline) + return oracle_spline_q(*Q, qt, *P1, *P2, *P3); + + // only spline at P + if((P1->spline || !P2->spline) && !Q->spline) + return oracle_spline_p(*Q, *P1, p1t, *P2, *P3, p3t); + + // spline at Q and P1 or P2 + return oracle_spline(prev, Q, P1, P2, P3); } + void LabelIntersections(Solid2d & sp, Solid2d & sq, Solid2d & sr, bool UNION) { auto & PP = sp.polys; @@ -1016,7 +1081,6 @@ void LabelIntersections(Solid2d & sp, Solid2d & sq, Solid2d & sr, bool UNION) if ( ( (Q_m_type == IS_P_m) && (Q_p_type == LEFT) ) || ( (Q_p_type == IS_P_m) && (Q_m_type == LEFT) ) ) I->label = ON_RIGHT; - cout << "label " << *I << " = " << I->label << endl; } // 2) classify intersection chains @@ -1028,7 +1092,6 @@ void LabelIntersections(Solid2d & sp, Solid2d & sq, Solid2d & sr, bool UNION) if (I->label == LEFT_ON || I->label == RIGHT_ON) { - cout << "intersection chain " << *I << endl; // remember status of the first chain vertex and vertex itself RelativePositionType x; From b21f04ddcbc5498148af497dec1b2fcd8b08b51a Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Thu, 14 Jan 2021 17:37:21 +0100 Subject: [PATCH 307/384] Update Ubuntu for tests to 20.10 --- tests/dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/dockerfile b/tests/dockerfile index 7c20b027..8e28c569 100644 --- a/tests/dockerfile +++ b/tests/dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:19.10 +FROM ubuntu:20.10 ENV DEBIAN_FRONTEND=noninteractive MAINTAINER Matthias Hochsteger RUN apt-get update && apt-get -y install python3 libpython3-dev libxmu-dev tk-dev tcl-dev cmake git g++ libglu1-mesa-dev ccache python3-pytest python3-numpy python3-tk clang-tidy python3-distutils clang libocct-data-exchange-dev libcgns-dev libhdf5-dev From 6f74a1580bb31057dbdd6c4eb60280eb55b63a20 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Thu, 14 Jan 2021 17:37:38 +0100 Subject: [PATCH 308/384] add test for csg2d, set maxh --- tests/pytest/test_csg2d.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/pytest/test_csg2d.py b/tests/pytest/test_csg2d.py index b76e9998..9e05682b 100644 --- a/tests/pytest/test_csg2d.py +++ b/tests/pytest/test_csg2d.py @@ -11,7 +11,7 @@ def check_area(geo, area): g.Add(geo) geo = g - m = geo.GenerateMesh() + m = geo.GenerateMesh(maxh=0.2) ngs = pytest.importorskip("ngsolve") mesh = ngs.Mesh(m) mesh.Curve(5) @@ -106,6 +106,7 @@ def test_circle_and_rect(): check_area(c+r, 3/4*pi+1) check_area(r*c, 1/4*pi) check_area(r+c, 3/4*pi+1) + check_area(r-c, 1-1/4*pi) if __name__ == "__main__": From 6b41cdac9fca3d69fa4e795112bb36b4b3e6296b Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Thu, 14 Jan 2021 18:18:42 +0100 Subject: [PATCH 309/384] install pytest-check --- .gitlab-ci.yml | 1 + tests/dockerfile | 2 +- tests/dockerfile_mpi | 4 ++-- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 0b4c60bc..b5ad6f13 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -70,6 +70,7 @@ test_win: <<: *win stage: test script: + - pip install pytest-check - cd tests\pytest - cd %NETGEN_BUILD_DIR%\netgen - ctest -C Release -V --output-on-failure diff --git a/tests/dockerfile b/tests/dockerfile index 8e28c569..152aab13 100644 --- a/tests/dockerfile +++ b/tests/dockerfile @@ -1,6 +1,6 @@ FROM ubuntu:20.10 ENV DEBIAN_FRONTEND=noninteractive MAINTAINER Matthias Hochsteger -RUN apt-get update && apt-get -y install python3 libpython3-dev libxmu-dev tk-dev tcl-dev cmake git g++ libglu1-mesa-dev ccache python3-pytest python3-numpy python3-tk clang-tidy python3-distutils clang libocct-data-exchange-dev libcgns-dev libhdf5-dev +RUN apt-get update && apt-get -y install python3 python3-pip libpython3-dev libxmu-dev tk-dev tcl-dev cmake git g++ libglu1-mesa-dev ccache python3-pytest python3-numpy python3-tk clang-tidy python3-distutils clang libocct-data-exchange-dev libcgns-dev libhdf5-dev RUN python3 -m pip install pytest-check ADD . /root/src/netgen diff --git a/tests/dockerfile_mpi b/tests/dockerfile_mpi index c90c0c28..a25a96b9 100644 --- a/tests/dockerfile_mpi +++ b/tests/dockerfile_mpi @@ -1,6 +1,6 @@ FROM ubuntu:20.04 ENV DEBIAN_FRONTEND=noninteractive MAINTAINER Matthias Hochsteger -RUN apt-get update && apt-get -y install python3 libpython3-dev python3-pip libxmu-dev tk-dev tcl-dev cmake git g++ libglu1-mesa-dev ccache python3-pytest python3-numpy python3-tk python3-mpi4py clang-tidy python3-distutils clang libopenmpi-dev openmpi-bin gfortran -RUN python3 -m pip install pytest-mpi pytest-check +RUN apt-get update && apt-get -y install python3 libpython3-dev python3-pip libxmu-dev tk-dev tcl-dev cmake git g++ libglu1-mesa-dev ccache python3-numpy python3-tk python3-mpi4py clang-tidy python3-distutils clang libopenmpi-dev openmpi-bin gfortran +RUN python3 -m pip install pytest-mpi pytest-check pytest ADD . /root/src/netgen From d1d3253408766cca3d1980e76d72e632bc35978b Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Tue, 26 Jan 2021 11:23:46 +0100 Subject: [PATCH 310/384] throw if optimize2d is called without geometry --- libsrc/meshing/python_mesh.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libsrc/meshing/python_mesh.cpp b/libsrc/meshing/python_mesh.cpp index 1b1a35a9..c125c3de 100644 --- a/libsrc/meshing/python_mesh.cpp +++ b/libsrc/meshing/python_mesh.cpp @@ -983,6 +983,8 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m) self.CalcLocalH(0.5); MeshingParameters mp; mp.optsteps2d = 5; + if(!self.GetGeometry()) + throw Exception("Cannot optimize surface mesh without geometry!"); Optimize2d (self, mp); },py::call_guard()) From b58c35831dac6a4f92955073aa90450e19020b9e Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Tue, 26 Jan 2021 11:27:46 +0100 Subject: [PATCH 311/384] Don't need to specify string description of spline type in 2d geom --- libsrc/geom2d/python_geom2d.cpp | 49 +++++++++++++++++++++++---------- 1 file changed, 35 insertions(+), 14 deletions(-) diff --git a/libsrc/geom2d/python_geom2d.cpp b/libsrc/geom2d/python_geom2d.cpp index 03f57398..7fc88d19 100644 --- a/libsrc/geom2d/python_geom2d.cpp +++ b/libsrc/geom2d/python_geom2d.cpp @@ -67,24 +67,45 @@ DLL_HEADER void ExportGeom2d(py::module &m) optional> bc, optional copy, double maxh, double hpref, double hprefleft, double hprefright) { - auto segtype = py::cast(segment[0]); - SplineSegExt * seg; - if (segtype == "line") + if(py::isinstance(segment[0])) { - LineSeg<2> * l = new LineSeg<2>(self.GetPoint(py::cast(segment[1])), - self.GetPoint(py::cast(segment[2]))); - seg = new SplineSegExt(*l); - } - else if (segtype == "spline3") - { - SplineSeg3<2> * seg3 = new SplineSeg3<2>(self.GetPoint(py::cast(segment[1])), - self.GetPoint(py::cast(segment[2])), - self.GetPoint(py::cast(segment[3]))); - seg = new SplineSegExt(*seg3); + auto segtype = py::cast(segment[0]); + + if (segtype == "line") + { + LineSeg<2> * l = new LineSeg<2>(self.GetPoint(py::cast(segment[1])), + self.GetPoint(py::cast(segment[2]))); + seg = new SplineSegExt(*l); + } + else if (segtype == "spline3") + { + SplineSeg3<2> * seg3 = new SplineSeg3<2>(self.GetPoint(py::cast(segment[1])), + self.GetPoint(py::cast(segment[2])), + self.GetPoint(py::cast(segment[3]))); + seg = new SplineSegExt(*seg3); + } + else + throw Exception("Appended segment is not a line or a spline3"); } else - throw Exception("Appended segment is not a line or a spline3"); + { + if(py::len(segment) == 2) + { + auto l = new LineSeg<2>(self.GetPoint(py::cast(segment[0])), + self.GetPoint(py::cast(segment[1]))); + seg = new SplineSegExt(*l); + } + else if(py::len(segment) == 3) + { + SplineSeg3<2> * seg3 = new SplineSeg3<2>(self.GetPoint(py::cast(segment[0])), + self.GetPoint(py::cast(segment[1])), + self.GetPoint(py::cast(segment[2]))); + seg = new SplineSegExt(*seg3); + } + else + throw Exception("Appended segment must either have 2 or 3 points"); + } seg->leftdom = leftdomain; seg->rightdom = rightdomain; seg->hmax = maxh; From 18dc32c51ad83c5b397d4f3874ea79f36326b354 Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Tue, 26 Jan 2021 15:33:21 +0100 Subject: [PATCH 312/384] Add RestrictHLine function in Python --- libsrc/meshing/python_mesh.cpp | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/libsrc/meshing/python_mesh.cpp b/libsrc/meshing/python_mesh.cpp index c125c3de..cb7c6ea9 100644 --- a/libsrc/meshing/python_mesh.cpp +++ b/libsrc/meshing/python_mesh.cpp @@ -1197,13 +1197,25 @@ project_boundaries : Optional[str] = None return mp; }), py::arg("mp")=nullptr, meshingparameter_description.c_str()) .def("__str__", &ToString) - .def("RestrictH", FunctionPointer - ([](MP & mp, double x, double y, double z, double h) + .def("RestrictH", [](MP & mp, double x, double y, double z, double h) { - mp.meshsize_points.Append ( MeshingParameters::MeshSizePoint (Point<3> (x,y,z), h)); - }), - py::arg("x"), py::arg("y"), py::arg("z"), py::arg("h") + mp.meshsize_points.Append ( MeshingParameters::MeshSizePoint(Point<3> (x,y,z), h)); + }, py::arg("x"), py::arg("y"), py::arg("z"), py::arg("h") ) + .def("RestrictH", [](MP & mp, const Point<3>& p, double h) + { + mp.meshsize_points.Append ({p, h}); + }, py::arg("p"), py::arg("h")) + .def("RestrictHLine", [](MP& mp, const Point<3>& p1, const Point<3>& p2, + double maxh) + { + int steps = int(Dist(p1, p2) / maxh) + 2; + auto v = p2 - p1; + for (int i = 0; i <= steps; i++) + { + mp.meshsize_points.Append({p1 + double(i)/steps * v, maxh}); + } + }, py::arg("p1"), py::arg("p2"), py::arg("maxh")) ; m.def("SetTestoutFile", FunctionPointer ([] (const string & filename) From f53c069308217848793d9da1e821d256b922f4a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20Sch=C3=B6berl?= Date: Sat, 30 Jan 2021 20:05:28 +0100 Subject: [PATCH 313/384] prepare SIMD for arm64 --- libsrc/core/CMakeLists.txt | 2 +- libsrc/core/simd.hpp | 4 + libsrc/core/simd_arm64.hpp | 146 +++++++++++++++++++++++++++++++++++++ 3 files changed, 151 insertions(+), 1 deletion(-) create mode 100644 libsrc/core/simd_arm64.hpp diff --git a/libsrc/core/CMakeLists.txt b/libsrc/core/CMakeLists.txt index 383bab85..3d6a438d 100644 --- a/libsrc/core/CMakeLists.txt +++ b/libsrc/core/CMakeLists.txt @@ -73,7 +73,7 @@ install(FILES ngcore.hpp archive.hpp type_traits.hpp version.hpp ngcore_api.hpp exception.hpp symboltable.hpp paje_trace.hpp utils.hpp profiler.hpp mpi_wrapper.hpp array.hpp taskmanager.hpp concurrentqueue.h localheap.hpp python_ngcore.hpp flags.hpp xbool.hpp signal.hpp bitarray.hpp table.hpp hashtable.hpp ranges.hpp - simd.hpp simd_avx.hpp simd_avx512.hpp simd_generic.hpp simd_sse.hpp + simd.hpp simd_avx.hpp simd_avx512.hpp simd_generic.hpp simd_sse.hpp simd_arm64.hpp DESTINATION ${NG_INSTALL_DIR_INCLUDE}/core COMPONENT netgen_devel) if(ENABLE_CPP_CORE_GUIDELINES_CHECK) diff --git a/libsrc/core/simd.hpp b/libsrc/core/simd.hpp index 0d69dec1..e809d6fe 100644 --- a/libsrc/core/simd.hpp +++ b/libsrc/core/simd.hpp @@ -26,6 +26,10 @@ #include "simd_avx512.hpp" #endif +#ifdef __arm64__ +#include "simd_arm64.hpp" +#endif + namespace ngcore { #ifdef NETGEN_ARCH_AMD64 diff --git a/libsrc/core/simd_arm64.hpp b/libsrc/core/simd_arm64.hpp new file mode 100644 index 00000000..c7137cb9 --- /dev/null +++ b/libsrc/core/simd_arm64.hpp @@ -0,0 +1,146 @@ +#ifdef NOTYETWORKING + +#include "arm_neon.h" + +namespace ngcore +{ + + template <> + class SIMD + { + int64x2_t mask; + public: + SIMD (int i) + { + mask[0] = i > 0; + mask[1] = i > 1; + } + + SIMD (bool i0, bool i1) { mask[0] = i0; mask[1] = i1; } + SIMD (SIMD i0, SIMD i1) { mask[0] = i0[0]; mask[1] = i1[0]; } + + //SIMD (__m128i _mask) : mask(_mask) { ; } + auto Data() const { return mask; } + static constexpr int Size() { return 2; } + // static NETGEN_INLINE SIMD GetMaskFromBits (unsigned int i); + int64_t operator[] (int i) const { return mask[i]; } + + auto Lo() const { return mask[0]; } + auto Hi() const { return mask[1]; } + }; + + + template<> + class SIMD + { + float64x2_t data; + + public: + static constexpr int Size() { return 2; } + SIMD () {} + SIMD (const SIMD &) = default; + SIMD (double v0, double v1) { data[0] = v0; data[1] = v1; } + + SIMD (std::array arr) + : data{(arr[0], arr[1])} + {} + + SIMD & operator= (const SIMD &) = default; + + SIMD (double val) { data[0] = data[1] = val; } + SIMD (int val) { data[0] = data[1] = double(val); } + SIMD (size_t val) { data[0] = data[1] = double(val); } + + SIMD (double const * p) + { + // data = vld1q_f64(p); + data[0] = p[0]; + data[1] = p[1]; + } + + SIMD (double const * p, SIMD mask) + { + data[0] = mask[0] ? p[0] : 0; + data[1] = mask[1] ? p[1] : 0; + } + SIMD (float64x2_t _data) { data = _data; } + + template>::value, int>::type = 0> + SIMD (const T & func) + { + data[0] = func(0); + data[1] = func(1); + } + + void Store (double * p) + { + // vst1q_f64(p, data); + p[0] = data[0]; + p[1] = data[1]; + } + + void Store (double * p, SIMD mask) + { + if (mask[0]) p[0] = data[0]; + if (mask[1]) p[1] = data[1]; + } + + NETGEN_INLINE double operator[] (int i) const { return ((double*)(&data))[i]; } + NETGEN_INLINE auto Data() const { return data; } + NETGEN_INLINE auto & Data() { return data; } + + + operator std::tuple () + { + auto pdata = (double*)&data; + return std::tuple(pdata[0], pdata[1]); + } + + double Lo() const { return data[0]; } + double Hi() const { return data[1]; } + }; + + + + NETGEN_INLINE double HSum (SIMD sd) + { + return sd[0]+sd[1]; + } + + NETGEN_INLINE SIMD HSum (SIMD a, SIMD b) + { + return SIMD (a[0]+a[1], b[0]+b[1]); + } + + // a*b+c + NETGEN_INLINE SIMD FMA (SIMD a, SIMD b, SIMD c) + { + return vmlaq_f64(c.Data(), a.Data(), b.Data()); + } + NETGEN_INLINE SIMD FMA (const double & a, SIMD b, SIMD c) + { + return FMA(SIMD (a), b, c); + } + // -a*b+c + NETGEN_INLINE SIMD FNMA (SIMD a, SIMD b, SIMD c) + { + return vmlsq_f64(c.Data(), a.Data(), b.Data()); + // return c-a*b; + } + NETGEN_INLINE SIMD FNMA (const double & a, SIMD b, SIMD c) + { + return FNMA(SIMD (a), b, c); + } + + NETGEN_INLINE SIMD If (SIMD a, SIMD b, SIMD c) + { + return { a[0] ? b[0] : c[0], a[1] ? b[1] : c[1] }; + } + NETGEN_INLINE SIMD If (SIMD a, SIMD b, SIMD c) + { + return SIMD (a[0] ? b[0] : c[0], a[1] ? b[1] : c[1]); + } + +} + +#endif From 18f5a933a9a3f6b7d181780e06a4f7fb8f3f9011 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20Sch=C3=B6berl?= Date: Sat, 30 Jan 2021 21:02:49 +0100 Subject: [PATCH 314/384] arm-simd working --- libsrc/core/simd_arm64.hpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/libsrc/core/simd_arm64.hpp b/libsrc/core/simd_arm64.hpp index c7137cb9..e3c70b8f 100644 --- a/libsrc/core/simd_arm64.hpp +++ b/libsrc/core/simd_arm64.hpp @@ -1,5 +1,3 @@ -#ifdef NOTYETWORKING - #include "arm_neon.h" namespace ngcore @@ -42,8 +40,11 @@ namespace ngcore SIMD (double v0, double v1) { data[0] = v0; data[1] = v1; } SIMD (std::array arr) - : data{(arr[0], arr[1])} - {} + // : data{(arr[0], arr[1])} + { + data[0] = arr[0]; + data[1] = arr[1]; + } SIMD & operator= (const SIMD &) = default; @@ -143,4 +144,3 @@ namespace ngcore } -#endif From 9a9828d3aff46dd3e37f0d2deed3216b2f0f50f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20Sch=C3=B6berl?= Date: Sun, 31 Jan 2021 16:31:47 +0100 Subject: [PATCH 315/384] some more arm-simds --- libsrc/core/simd_arm64.hpp | 66 +++++++++++++++++++++++++------------- 1 file changed, 43 insertions(+), 23 deletions(-) diff --git a/libsrc/core/simd_arm64.hpp b/libsrc/core/simd_arm64.hpp index e3c70b8f..34cf1862 100644 --- a/libsrc/core/simd_arm64.hpp +++ b/libsrc/core/simd_arm64.hpp @@ -10,14 +10,13 @@ namespace ngcore public: SIMD (int i) { - mask[0] = i > 0; - mask[1] = i > 1; + mask[0] = i > 0 ? -1 : 0; + mask[1] = i > 1 ? -1 : 0; } - SIMD (bool i0, bool i1) { mask[0] = i0; mask[1] = i1; } + SIMD (bool i0, bool i1) { mask[0] = i0 ? -1:0; mask[1] = i1 ? -1 : 0; } SIMD (SIMD i0, SIMD i1) { mask[0] = i0[0]; mask[1] = i1[0]; } - - //SIMD (__m128i _mask) : mask(_mask) { ; } + SIMD (float64x2_t _data) : mask{_data} { } auto Data() const { return mask; } static constexpr int Size() { return 2; } // static NETGEN_INLINE SIMD GetMaskFromBits (unsigned int i); @@ -37,26 +36,21 @@ namespace ngcore static constexpr int Size() { return 2; } SIMD () {} SIMD (const SIMD &) = default; - SIMD (double v0, double v1) { data[0] = v0; data[1] = v1; } - - SIMD (std::array arr) - // : data{(arr[0], arr[1])} - { - data[0] = arr[0]; - data[1] = arr[1]; - } - + // SIMD (double v0, double v1) : data{v0,v1} { } + SIMD (double v0, double v1) : data{vcombine_f64(float64x1_t{v0}, float64x1_t{v1})} { } + SIMD (std::array arr) : data{arr[0], arr[1]} { } + SIMD & operator= (const SIMD &) = default; - SIMD (double val) { data[0] = data[1] = val; } - SIMD (int val) { data[0] = data[1] = double(val); } - SIMD (size_t val) { data[0] = data[1] = double(val); } + SIMD (double val) : data{val,val} { } + SIMD (int val) : data{double(val),double(val)} { } + SIMD (size_t val) : data{double(val),double(val)} { } SIMD (double const * p) { - // data = vld1q_f64(p); - data[0] = p[0]; - data[1] = p[1]; + data = vld1q_f64(p); + // data[0] = p[0]; + // data[1] = p[1]; } SIMD (double const * p, SIMD mask) @@ -75,9 +69,11 @@ namespace ngcore void Store (double * p) { - // vst1q_f64(p, data); + vst1q_f64(p, data); + /* p[0] = data[0]; p[1] = data[1]; + */ } void Store (double * p, SIMD mask) @@ -86,7 +82,8 @@ namespace ngcore if (mask[1]) p[1] = data[1]; } - NETGEN_INLINE double operator[] (int i) const { return ((double*)(&data))[i]; } + // NETGEN_INLINE double operator[] (int i) const { return ((double*)(&data))[i]; } + NETGEN_INLINE double operator[] (int i) const { return data[i]; } NETGEN_INLINE auto Data() const { return data; } NETGEN_INLINE auto & Data() { return data; } @@ -99,6 +96,7 @@ namespace ngcore double Lo() const { return data[0]; } double Hi() const { return data[1]; } + // __ai float64x1_t vget_high_f64(float64x2_t __p0) { }; @@ -132,15 +130,37 @@ namespace ngcore { return FNMA(SIMD (a), b, c); } + + NETGEN_INLINE SIMD operator+ (SIMD a, SIMD b) + { return a.Data()+b.Data(); } + + NETGEN_INLINE SIMD operator- (SIMD a, SIMD b) + { return a.Data()-b.Data(); } + NETGEN_INLINE SIMD operator- (SIMD a) + { return -a.Data(); } + + NETGEN_INLINE SIMD operator* (SIMD a, SIMD b) + { return a.Data()*b.Data(); } + + NETGEN_INLINE SIMD operator/ (SIMD a, SIMD b) + { return a.Data()/b.Data(); } + + NETGEN_INLINE SIMD If (SIMD a, SIMD b, SIMD c) { - return { a[0] ? b[0] : c[0], a[1] ? b[1] : c[1] }; + // return { a[0] ? b[0] : c[0], a[1] ? b[1] : c[1] }; + return vbslq_f64(a.Data(), b.Data(), c.Data()); } NETGEN_INLINE SIMD If (SIMD a, SIMD b, SIMD c) { return SIMD (a[0] ? b[0] : c[0], a[1] ? b[1] : c[1]); } + + NETGEN_INLINE SIMD operator&& (SIMD a, SIMD b) + { + return vandq_u64 (a.Data(), b.Data()); + } } From 7739aaedf7031eaae08026f129271160ea480a61 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Mon, 1 Feb 2021 11:27:26 +0100 Subject: [PATCH 316/384] SplineGeometry - also add point elements with empty names to mesh --- libsrc/geom2d/genmesh2d.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libsrc/geom2d/genmesh2d.cpp b/libsrc/geom2d/genmesh2d.cpp index 61753f72..5cb9fa58 100644 --- a/libsrc/geom2d/genmesh2d.cpp +++ b/libsrc/geom2d/genmesh2d.cpp @@ -271,7 +271,6 @@ namespace netgen // add point elements for (auto & point : geompoints) - if (point.name.length()) { Point<3> newp(point(0), point(1), 0); PointIndex npi = mesh2d.AddPoint (newp, 1, FIXEDPOINT); From 50238564324b07dee1ba04d4bd7750d0f7caae69 Mon Sep 17 00:00:00 2001 From: Michael Date: Mon, 1 Feb 2021 15:29:17 +0100 Subject: [PATCH 317/384] improve curving trigs with u,v coordinates by better initial guess --- libsrc/meshing/curvedelems.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libsrc/meshing/curvedelems.cpp b/libsrc/meshing/curvedelems.cpp index 91f3c473..70031bdd 100644 --- a/libsrc/meshing/curvedelems.cpp +++ b/libsrc/meshing/curvedelems.cpp @@ -1261,8 +1261,10 @@ namespace netgen SurfaceElementIndex sei = top.GetFace2SurfaceElement (f+1)-1; if (sei != SurfaceElementIndex(-1)) { PointGeomInfo gi = mesh[sei].GeomInfoPi(1); - gi.u = 1.0/3.0*(mesh[sei].GeomInfoPi(1).u+mesh[sei].GeomInfoPi(2).u+mesh[sei].GeomInfoPi(3).u); - gi.v = 1.0/3.0*(mesh[sei].GeomInfoPi(1).v+mesh[sei].GeomInfoPi(2).v+mesh[sei].GeomInfoPi(3).v); + // use improved initial guess + gi.u = (lami[fnums[0]]*mesh[sei].GeomInfoPi(1).u+lami[fnums[1]]*mesh[sei].GeomInfoPi(2).u+lami[fnums[2]]*mesh[sei].GeomInfoPi(3).u); + gi.v = (lami[fnums[0]]*mesh[sei].GeomInfoPi(1).v+lami[fnums[1]]*mesh[sei].GeomInfoPi(2).v+lami[fnums[2]]*mesh[sei].GeomInfoPi(3).v); + geo.ProjectPointGI(surfnr[facenr], pp, gi); } else From 461952528023a3e2c29cf614270233aededfe730 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Tue, 2 Feb 2021 18:58:54 +0100 Subject: [PATCH 318/384] allow empty names in mesh file --- libsrc/meshing/meshclass.cpp | 55 ++++++++++++++++++++++++++---------- 1 file changed, 40 insertions(+), 15 deletions(-) diff --git a/libsrc/meshing/meshclass.cpp b/libsrc/meshing/meshclass.cpp index 6234f1eb..c133c8e1 100644 --- a/libsrc/meshing/meshclass.cpp +++ b/libsrc/meshing/meshclass.cpp @@ -889,6 +889,30 @@ namespace netgen + // Reads mandatory integer and optional string token from input stream + // used for parsing bcnames, cd2names etc. + void ReadNumberAndName( istream & infile, int & i, string & s ) + { + string line; + std::istringstream iline; + + bool empty_line = true; + + while(empty_line && infile) + { + std::getline(infile, line); + iline = std::istringstream{line}; + iline >> i; + + if(iline) + empty_line = false; + + iline >> s; + } + + if(!infile) + throw Exception("Reached end of file while parsing"); + } void Mesh :: Load (istream & infile) { @@ -1137,11 +1161,11 @@ namespace netgen if (strcmp (str, "materials") == 0) { infile >> n; - for (i = 1; i <= n; i++) + for ( auto i : Range(n) ) { int nr; string mat; - infile >> nr >> mat; + ReadNumberAndName( infile, nr, mat ); SetMaterial (nr, mat.c_str()); } } @@ -1149,13 +1173,13 @@ namespace netgen if ( strcmp (str, "bcnames" ) == 0 ) { infile >> n; - NgArray bcnrs(n); + Array bcnrs(n); SetNBCNames(n); - for ( i = 1; i <= n; i++ ) + for ( auto i : Range(n) ) { string nextbcname; - infile >> bcnrs[i-1] >> nextbcname; - bcnames[bcnrs[i-1]-1] = new string(nextbcname); + ReadNumberAndName( infile, bcnrs[i], nextbcname ); + bcnames[bcnrs[i]-1] = new string(nextbcname); } if ( GetDimension() == 3 ) @@ -1179,14 +1203,14 @@ namespace netgen if ( strcmp (str, "cd2names" ) == 0) { infile >> n; - NgArray cd2nrs(n); + Array cd2nrs(n); SetNCD2Names(n); - for( i=1; i<=n; i++) - { - string nextcd2name; - infile >> cd2nrs[i-1] >> nextcd2name; - cd2names[cd2nrs[i-1]-1] = new string(nextcd2name); - } + for ( auto i : Range(n) ) + { + string nextcd2name; + ReadNumberAndName( infile, cd2nrs[i], nextcd2name ); + cd2names[cd2nrs[i]-1] = new string(nextcd2name); + } if (GetDimension() == 2) { throw NgException("co dim 2 elements not implemented for dimension 2"); @@ -1196,11 +1220,12 @@ namespace netgen if ( strcmp (str, "cd3names" ) == 0) { infile >> n; - NgArray cd3nrs(n); + Array cd3nrs(n); SetNCD3Names(n); - for( i=1; i<=n; i++) + for( auto i : Range(n) ) { string nextcd3name; + ReadNumberAndName( infile, cd3nrs[i], nextcd3name ); infile >> cd3nrs[i-1] >> nextcd3name; cd3names[cd3nrs[i-1]-1] = new string(nextcd3name); } From 221d3f5a9a59545a9c2ee2c66807bed6317da880 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Tue, 2 Feb 2021 18:59:32 +0100 Subject: [PATCH 319/384] delete pointelements after parallel mesh send (TODO: send pointelements!) --- libsrc/meshing/parallelmesh.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libsrc/meshing/parallelmesh.cpp b/libsrc/meshing/parallelmesh.cpp index e2c5aed2..9e624cba 100644 --- a/libsrc/meshing/parallelmesh.cpp +++ b/libsrc/meshing/parallelmesh.cpp @@ -789,6 +789,7 @@ namespace netgen self.surfelements = Array(0); self.volelements = Array(0); self.segments = Array(0); + self.pointelements = Array(0); self.lockedpoints = Array(0); auto cleanup_ptr = [](auto & ptr) { if (ptr != nullptr) { From 22aee3b3a55243631fefbc8cc01cca5b7521cf17 Mon Sep 17 00:00:00 2001 From: Joachim Schoeberl Date: Fri, 5 Feb 2021 11:42:45 +0100 Subject: [PATCH 320/384] simd-mapping of point elements --- libsrc/interface/nginterface_v2.cpp | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/libsrc/interface/nginterface_v2.cpp b/libsrc/interface/nginterface_v2.cpp index 18563f91..cca8b3a4 100644 --- a/libsrc/interface/nginterface_v2.cpp +++ b/libsrc/interface/nginterface_v2.cpp @@ -861,7 +861,14 @@ namespace netgen SIMD * x, size_t sx, SIMD * dxdxi, size_t sdxdxi) const { - cout << "MultiElementtransformation<0,2> simd not implemented" << endl; + //cout << "MultiElementtransformation<0,2> simd not implemented" << endl; + + PointIndex pi = mesh->pointelements[elnr].pnum; + Point<3> xg = mesh->Point(pi); + if (x) + for (int j = 0; j < npts; j++) + for (int i = 0; i < 2; i++) + x[j*sx+i] = xg(i); } template<> DLL_HEADER void Ngx_Mesh :: @@ -870,7 +877,13 @@ namespace netgen SIMD * x, size_t sx, SIMD * dxdxi, size_t sdxdxi) const { - cout << "multi-eltrafo simd called, 0,1,simd" << endl; + //cout << "multi-eltrafo simd called, 0,1,simd" << endl; + PointIndex pi = mesh->pointelements[elnr].pnum; + Point<3> xg = mesh->Point(pi); + if (x) + for (int j = 0; j < npts; j++) + for (int i = 0; i < 1; i++) + x[j*sx+i] = xg(i); } template<> DLL_HEADER void Ngx_Mesh :: From 25011c8407188765c27972216be86a0d5a10152b Mon Sep 17 00:00:00 2001 From: Joachim Schoeberl Date: Fri, 5 Feb 2021 11:59:03 +0100 Subject: [PATCH 321/384] arm-simd: HSum, tuple support --- libsrc/core/simd_arm64.hpp | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/libsrc/core/simd_arm64.hpp b/libsrc/core/simd_arm64.hpp index 34cf1862..f2572d34 100644 --- a/libsrc/core/simd_arm64.hpp +++ b/libsrc/core/simd_arm64.hpp @@ -21,7 +21,10 @@ namespace ngcore static constexpr int Size() { return 2; } // static NETGEN_INLINE SIMD GetMaskFromBits (unsigned int i); int64_t operator[] (int i) const { return mask[i]; } - + + template + int64_t Get() const { return mask[I]; } + auto Lo() const { return mask[0]; } auto Hi() const { return mask[1]; } }; @@ -84,31 +87,37 @@ namespace ngcore // NETGEN_INLINE double operator[] (int i) const { return ((double*)(&data))[i]; } NETGEN_INLINE double operator[] (int i) const { return data[i]; } + NETGEN_INLINE double & operator[] (int i) { return ((double*)&data)[i]; } + + template + double Get() const { return data[I]; } + NETGEN_INLINE auto Data() const { return data; } NETGEN_INLINE auto & Data() { return data; } - operator std::tuple () { auto pdata = (double*)&data; return std::tuple(pdata[0], pdata[1]); } - double Lo() const { return data[0]; } - double Hi() const { return data[1]; } - // __ai float64x1_t vget_high_f64(float64x2_t __p0) { + double Lo() const { return Get<0>(); } // data[0]; } + double Hi() const { return Get<1>(); } // data[1]; } + // double Hi() const { return vget_high_f64(data)[0]; } }; NETGEN_INLINE double HSum (SIMD sd) { - return sd[0]+sd[1]; + return sd.Lo()+sd.Hi(); // sd[0]+sd[1]; } NETGEN_INLINE SIMD HSum (SIMD a, SIMD b) { - return SIMD (a[0]+a[1], b[0]+b[1]); + // return SIMD (a[0]+a[1], b[0]+b[1]); + return vpaddq_f64(a.Data(), b.Data()); + } // a*b+c From 1d9281f41222a07fcdaf18c8f640908bcb46135b Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Fri, 5 Feb 2021 12:10:22 +0100 Subject: [PATCH 322/384] localh as shared_ptr in mesh --- libsrc/meshing/meshclass.hpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/libsrc/meshing/meshclass.hpp b/libsrc/meshing/meshclass.hpp index 3bdaf219..6faae381 100644 --- a/libsrc/meshing/meshclass.hpp +++ b/libsrc/meshing/meshclass.hpp @@ -69,7 +69,7 @@ namespace netgen /** Representation of local mesh-size h */ - unique_ptr lochfunc; + shared_ptr lochfunc; /// double hglob; /// @@ -465,6 +465,10 @@ namespace netgen bool HasLocalHFunction () { return lochfunc != nullptr; } /// LocalH & LocalHFunction () { return * lochfunc; } + + shared_ptr GetLocalH() const { return lochfunc; } + void SetLocalH(shared_ptr loch) { lochfunc = loch; } + /// bool LocalHFunctionGenerated(void) const { return (lochfunc != NULL); } From 9e080ee9e0f9acdfff457ea98f18ef376e846685 Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Fri, 5 Feb 2021 12:16:41 +0100 Subject: [PATCH 323/384] add boundarylayer closure on pyramids outside --- libsrc/meshing/boundarylayer.cpp | 108 ++++++++++++++++++++----------- 1 file changed, 70 insertions(+), 38 deletions(-) diff --git a/libsrc/meshing/boundarylayer.cpp b/libsrc/meshing/boundarylayer.cpp index 3fe25adc..d0bfe335 100644 --- a/libsrc/meshing/boundarylayer.cpp +++ b/libsrc/meshing/boundarylayer.cpp @@ -513,50 +513,82 @@ namespace netgen } if(do_insert) { - if(el.GetType() != TET) - throw Exception("Boundarylayer only implemented for tets outside yet!"); - if(moved.Size() == 2) + if(el.GetType() == TET) { - 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)) + if(moved.Size() == 2) { - 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(fixed.Size() == 2) + throw Exception("This should not be possible!"); + PointIndex p1 = moved[0]; + PointIndex p2 = moved[1]; + for(auto i : Range(blp.heights)) { - if(p == moved[0]) - p = p1; - else if(p == fixed[0]) - p = p2; + 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); } - p1 = p2; - mesh.AddVolumeElement(nel); } } + else if(el.GetType() == PYRAMID) + { + if(moved.Size() == 2) + { + if(fixed.Size() != 2) + throw Exception("This case is not implemented yet! Fixed size = " + ToString(fixed.Size())); + PointIndex p1 = moved[0]; + PointIndex p2 = moved[1]; + for(auto i : Range(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] + el[4] - fixed[0] - fixed[1] - moved[0] - moved[1]; + if(Cross(mesh[p2] - mesh[p1], mesh[p4]-mesh[p1]) * (mesh[nel[4]]-mesh[nel[1]]) > 0) + Swap(nel[1], nel[3]); + nel.SetIndex(el.GetIndex()); + mesh.AddVolumeElement(nel); + p1 = p4; + p2 = p3; + } + } + else if(moved.Size() == 1) + throw Exception("This case is not implemented yet!"); + } + else + throw Exception("Boundarylayer only implemented for tets and pyramids outside yet!"); } } From 6d30186279f8ea83e6b5d06431a5005646ee7360 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Fri, 5 Feb 2021 17:40:43 +0100 Subject: [PATCH 324/384] allow cd2names in 2d meshes --- libsrc/meshing/meshclass.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libsrc/meshing/meshclass.cpp b/libsrc/meshing/meshclass.cpp index c133c8e1..cac7dc97 100644 --- a/libsrc/meshing/meshclass.cpp +++ b/libsrc/meshing/meshclass.cpp @@ -1211,9 +1211,9 @@ namespace netgen ReadNumberAndName( infile, cd2nrs[i], nextcd2name ); cd2names[cd2nrs[i]-1] = new string(nextcd2name); } - if (GetDimension() == 2) + if (GetDimension() < 2) { - throw NgException("co dim 2 elements not implemented for dimension 2"); + throw NgException("co dim 2 elements not implemented for dimension < 2"); } } From fd878079cb51777ebc7bf19e28d9a4c89e33a5a6 Mon Sep 17 00:00:00 2001 From: Joachim Schoeberl Date: Mon, 8 Feb 2021 09:41:14 +0100 Subject: [PATCH 325/384] edge hierarchy in mesh - Topology class, needs mesh.EnableTable('parentedges') --- libsrc/include/nginterface_v2.hpp | 4 + libsrc/include/nginterface_v2_impl.hpp | 14 ++ libsrc/meshing/meshclass.hpp | 4 +- libsrc/meshing/python_mesh.cpp | 7 +- libsrc/meshing/topology.cpp | 209 +++++++++++++++++++++++++ libsrc/meshing/topology.hpp | 21 ++- 6 files changed, 255 insertions(+), 4 deletions(-) diff --git a/libsrc/include/nginterface_v2.hpp b/libsrc/include/nginterface_v2.hpp index fc1b860f..82074cfc 100644 --- a/libsrc/include/nginterface_v2.hpp +++ b/libsrc/include/nginterface_v2.hpp @@ -355,6 +355,10 @@ namespace netgen int GetParentElement (int ei) const; int GetParentSElement (int ei) const; + bool HasParentEdges() const; + tuple> GetParentEdges (int enr) const; + tuple> GetParentFaces (int fnr) const; + int GetNIdentifications() const; int GetIdentificationType(int idnr) const; Ng_Buffer GetPeriodicVertices(int idnr) const; diff --git a/libsrc/include/nginterface_v2_impl.hpp b/libsrc/include/nginterface_v2_impl.hpp index 20fccd2a..cd9a6c4b 100644 --- a/libsrc/include/nginterface_v2_impl.hpp +++ b/libsrc/include/nginterface_v2_impl.hpp @@ -336,6 +336,20 @@ NGX_INLINE void Ngx_Mesh :: GetParentNodes (int ni, int * parents) const parents[0] = parents[1] = -1; } +inline bool Ngx_Mesh :: HasParentEdges() const +{ + return mesh->GetTopology().HasParentEdges(); +} + +inline tuple> Ngx_Mesh :: GetParentEdges (int enr) const +{ + return mesh->GetTopology().GetParentEdges(enr); +} + +inline tuple> Ngx_Mesh :: GetParentFaces (int fnr) const +{ + return mesh->GetTopology().GetParentFaces(fnr); +} inline auto Ngx_Mesh :: GetTimeStamp() const { return mesh->GetTimeStamp(); } diff --git a/libsrc/meshing/meshclass.hpp b/libsrc/meshing/meshclass.hpp index 6faae381..65ff082f 100644 --- a/libsrc/meshing/meshclass.hpp +++ b/libsrc/meshing/meshclass.hpp @@ -779,8 +779,8 @@ namespace netgen DLL_HEADER bool PureTetMesh () const; - const MeshTopology & GetTopology () const - { return topology; } + const MeshTopology & GetTopology () const { return topology; } + MeshTopology & GetTopology () { return topology; } DLL_HEADER void UpdateTopology (NgTaskManager tm = &DummyTaskManager, NgTracer tracer = &DummyTracer); diff --git a/libsrc/meshing/python_mesh.cpp b/libsrc/meshing/python_mesh.cpp index cb7c6ea9..5c92d3dd 100644 --- a/libsrc/meshing/python_mesh.cpp +++ b/libsrc/meshing/python_mesh.cpp @@ -1131,8 +1131,13 @@ project_boundaries : Optional[str] = None { if (name == "edges") const_cast(self.GetTopology()).SetBuildEdges(set); - if (name == "faces") + else if (name == "faces") const_cast(self.GetTopology()).SetBuildFaces(set); + else if (name == "parentedges") + const_cast(self.GetTopology()).SetBuildHierarchy(set); + else + throw Exception ("noting known about table "+name +"\n" + "knwon are 'edges', 'faces', 'parentedges'"); }, py::arg("name"), py::arg("set")=true) diff --git a/libsrc/meshing/topology.cpp b/libsrc/meshing/topology.cpp index 65dca902..fe6a6621 100644 --- a/libsrc/meshing/topology.cpp +++ b/libsrc/meshing/topology.cpp @@ -677,6 +677,215 @@ namespace netgen }); } } ); + + + if (build_hierarchy) + { + static Timer t("build_hierarchy"); RegionTimer reg(t); + cnt = 0; + for (size_t i = 0; i < edge2vert.Size(); i++) + cnt[edge2vert[i][0]]++; + TABLE vert2edge (cnt); + for (size_t i = 0; i < edge2vert.Size(); i++) + vert2edge.AddSave (edge2vert[i][0], i); + + // build edge hierarchy: + parent_edges.SetSize (ned); + parent_edges = { -1, { -1, -1, -1 } }; + /* + cout << "mlbetween = " << mesh->mlbetweennodes.Size() << endl; + cout << "mlbetween = " << endl << mesh->mlbetweennodes << endl; + cout << "v2e = " << endl << vert2edge << endl; + cout << "e2v = " << endl << edge2vert << endl; + cout << "ned = " << ned << endl; + */ + for (size_t i = 0; i < ned; i++) + { + // cout << " ref edge " << i << "/" << ned << endl; + /* + int pa1[2], pa2[2]; + ma->GetParentNodes (i2[0], pa1); + ma->GetParentNodes (i2[1], pa2); + */ + auto i2 = edge2vert[i]; + + if (i2[0] > mesh->mlbetweennodes.Size()+PointIndex::BASE || + i2[1] > mesh->mlbetweennodes.Size()+PointIndex::BASE) + continue; + + // cout << "i2 = " << i2 << endl; + auto pa1 = mesh->mlbetweennodes[i2[0]]; + auto pa2 = mesh->mlbetweennodes[i2[1]]; + + // cout << "pa1 = " << pa1 << endl; + // cout << "pa2 = " << pa2 << endl; + //if (pa1[0] == -1 && pa2[0] == -1) + // continue; + + // both vertices are on coarsest mesh + if (!pa1[0].IsValid() && !pa2[0].IsValid()) + continue; + + + int issplitedge = 0; + if (pa1[0] == i2[1] || pa1[1] == i2[1]) + issplitedge = 1; + if (pa2[0] == i2[0] || pa2[1] == i2[0]) + issplitedge = 2; + + if (issplitedge) + { + // cout << "split edge " << endl; + // edge is obtained by splitting one edge into two parts: + INT<2> paedge; + if (issplitedge == 1) + paedge = INT<2> (pa1[0], pa1[1]); + else + paedge = INT<2> (pa2[0], pa2[1]); + + if (paedge[0] > paedge[1]) + Swap (paedge[0], paedge[1]); + + for (int ednr : vert2edge[paedge[0]]) + if (auto ic2 = edge2vert[ednr]; ic2[1] == paedge[1]) + { + // cout << "matching: " << ednr << endl; + int orient = (paedge[0] == i2[0] || paedge[1] == i2[1]) ? 1 : 0; + parent_edges[i] = { orient, { ednr, -1, -1 } }; + } + } + else + { + // edge is splitting edge in middle of triangle: + for (int j = 1; j <= 2; j++) + { + INT<2> paedge1, paedge2; + if (j == 1) + { + paedge1 = INT<2> (pa1[0], i2[1]); + paedge2 = INT<2> (pa1[1], i2[1]); + } + else + { + paedge1 = INT<2> (pa2[0], i2[0]); + paedge2 = INT<2> (pa2[1], i2[0]); + } + if (paedge1[0] > paedge1[1]) + Swap (paedge1[0], paedge1[1]); + if (paedge2[0] > paedge2[1]) + Swap (paedge2[0], paedge2[1]); + + // cout << "paedge1 = " << paedge1 << ", paedge2 = " << paedge2 << endl; + // if first vertex number is -1, then don't try to find entry in node2edge hash table + if ( paedge1[0] == PointIndex::BASE-1 || paedge2[0] == PointIndex::BASE-1 ) + continue; + + int paedgenr1=-1, paedgenr2=-1, orient1 = 0, orient2 = 0; + for (int ednr : vert2edge[paedge1[0]]) + if (auto ic2 = edge2vert[ednr]; ic2[1] == paedge1[1]) + { + paedgenr1 = ednr; + // cout << "ednr = " << ednr << ", i2 = " << i2 << endl; + orient1 = (paedge1[0] == i2[0] || paedge1[1] == i2[1]) ? 1 : 0; + // cout << "orient1 = " << orient1 << endl; + } + for (int ednr : vert2edge[paedge2[0]]) + if (auto ic2 = edge2vert[ednr]; ic2[1] == paedge2[1]) + { + paedgenr2 = ednr; + // cout << "ednr = " << ednr << ", i2 = " << i2 << endl; + orient2 = (paedge2[0] == i2[0] || paedge2[1] == i2[1]) ? 1 : 0; + // cout << "orient2 = " << orient2 << endl; + } + if (paedgenr1 != -1 && paedgenr2 != -1) + parent_edges[i] = { orient1+2*orient2, { paedgenr1, paedgenr2, -1 } }; + } + + + // TODO: quad edges + /* + if (parentedges[i][0] == -1) + { + // quad split + if (pa1[0] != pa2[0] && + pa1[0] != pa2[1] && + pa1[1] != pa2[0] && + pa1[1] != pa2[1]) + for (int j = 1; j <= 2; j++) + { + INT<2> paedge1, paedge2; + if (j == 1) + { + paedge1 = INT<2> (pa1[0], pa2[0]); + paedge2 = INT<2> (pa1[1], pa2[1]); + } + else + { + paedge1 = INT<2> (pa1[0], pa2[1]); + paedge2 = INT<2> (pa1[1], pa2[0]); + } + + int paedgenr1 = 0, paedgenr2 = 0; + int orient1 = 1, orient2 = 1; + + if (paedge1[0] > paedge1[1]) + { + Swap (paedge1[0], paedge1[1]); + orient1 = 0; + } + if (paedge2[0] > paedge2[1]) + { + Swap (paedge2[0], paedge2[1]); + orient2 = 0; + } + + if ( paedge1[0] == -1 || paedge2[0] == -1 ) + continue; + + if (node2edge.Used (paedge1) && node2edge.Used (paedge2)) + { + paedgenr1 = node2edge.Get (paedge1); + paedgenr2 = node2edge.Get (paedge2); + parentedges[i][0] = 2 * paedgenr1 + orient1; + parentedges[i][1] = 2 * paedgenr2 + orient2; + } + } + } + + if (parentedges[i][0] == -1) + { + // triangle split into quad+trig (from anisotropic pyramids) + for (int j = 0; j < 2; j++) + for (int k = 0; k < 2; k++) + { + INT<2> paedge (pa1[1-j], pa2[1-k]); + int orientpa = 1; + if (paedge[0] > paedge[1]) + { + Swap (paedge[0], paedge[1]); + orientpa = 0; + } + if (pa1[j] == pa2[k] && node2edge.Used(paedge)) + { + int paedgenr = node2edge.Get (paedge); + parentedges[i][0] = 2 * paedgenr + orientpa; + } + } + + } + */ + + } + + } + + + for (int i : Range(parent_edges)) + { + auto [info, nrs] = parent_edges[i]; + // cout << "edge " << i << " has " << info << ", nrs = " << nrs[0] << " " << nrs[1] << endl; + } + } } diff --git a/libsrc/meshing/topology.hpp b/libsrc/meshing/topology.hpp index 00f599f6..2a9c3c9b 100644 --- a/libsrc/meshing/topology.hpp +++ b/libsrc/meshing/topology.hpp @@ -27,6 +27,7 @@ struct T_FACE int fnr; // 0-based }; + /* template struct FixArray { @@ -34,13 +35,17 @@ struct T_FACE T & operator[] (size_t i) { return vals[i]; } T operator[] (size_t i) const { return vals[i]; } }; - + */ + + template + using FixArray = std::array; class MeshTopology { const Mesh * mesh; bool buildedges; bool buildfaces; + bool build_hierarchy = false; // may be changed to default = false NgArray edge2vert; NgArray face2vert; @@ -75,11 +80,14 @@ public: { buildedges = be; } void SetBuildFaces (bool bf) { buildfaces = bf; } + void SetBuildHierarchy (bool bh) { build_hierarchy = bh; } bool HasEdges () const { return buildedges; } bool HasFaces () const { return buildfaces; } + bool HasParentEdges () const + { return build_hierarchy; } void Update(NgTaskManager tm = &DummyTaskManager, NgTracer tracer = &DummyTracer); bool NeedsUpdate() const; @@ -178,6 +186,17 @@ public: int GetVerticesEdge ( int v1, int v2) const; void GetSegmentVolumeElements ( int segnr, NgArray & els ) const; void GetSegmentSurfaceElements ( int segnr, NgArray & els ) const; + + +private: + Array>> parent_edges; + void BuildParentEdges (); + + Array>> parent_faces; + void BuildParentFaces (); +public: + auto GetParentEdges (int enr) const { return parent_edges[enr]; } + auto GetParentFaces (int fnr) const { return parent_faces[fnr]; } }; From 145007b46a1fa038a93a4740bc9918d35898ba06 Mon Sep 17 00:00:00 2001 From: Joachim Schoeberl Date: Mon, 8 Feb 2021 10:48:41 +0100 Subject: [PATCH 326/384] use the right INT --- libsrc/meshing/topology.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsrc/meshing/topology.cpp b/libsrc/meshing/topology.cpp index fe6a6621..09a73f3c 100644 --- a/libsrc/meshing/topology.cpp +++ b/libsrc/meshing/topology.cpp @@ -4,7 +4,7 @@ namespace netgen { using ngcore::ParallelForRange; - + using ngcore::INT; template void QuickSortRec (NgFlatArray data, From d1bc4fc6ca69adcd1fd3bbf87d0778e26d7c84c8 Mon Sep 17 00:00:00 2001 From: Lukas Date: Mon, 8 Feb 2021 11:36:48 +0100 Subject: [PATCH 327/384] fix OCC curving with MPI --- libsrc/meshing/parallelmesh.cpp | 158 ++++++++++++++++++++++++-------- 1 file changed, 121 insertions(+), 37 deletions(-) diff --git a/libsrc/meshing/parallelmesh.cpp b/libsrc/meshing/parallelmesh.cpp index 9e624cba..e2f9cbdc 100644 --- a/libsrc/meshing/parallelmesh.cpp +++ b/libsrc/meshing/parallelmesh.cpp @@ -32,9 +32,111 @@ namespace ngcore { } */ -namespace netgen +namespace ngcore { + /** An MPI-Package for a Surface element **/ + class SurfPointPackage + { + public: + int num; // point numebr + int trignum; // STL geo info + double u, v; // OCC geo info + SurfPointPackage () { ; } + SurfPointPackage & operator = (const SurfPointPackage & other) { + num = other.num; + trignum = other.trignum; + u = other.u; + v = other.v; + return *this; + } + }; // class SurfPointPackage + + template<> struct MPI_typetrait { + static MPI_Datatype MPIType () { + static MPI_Datatype MPI_T = 0; + if (!MPI_T) + { + int block_len[2] = { 2, 2 }; + MPI_Aint displs[3] = { 0, 2*sizeof(int) }; + MPI_Datatype types[2] = { MPI_INT, MPI_DOUBLE }; + MPI_Type_create_struct(2, block_len, displs, types, &MPI_T); + MPI_Type_commit(&MPI_T); + } + return MPI_T; + } + }; // struct MPI_typetrait + + + class SelPackage + { + public: + int sei; + int index; + int np; + /** we send too much here, especially in 2d! **/ + SurfPointPackage points[ELEMENT2D_MAXPOINTS]; + SelPackage () { ; } + SelPackage (const netgen::Mesh & mesh, netgen::SurfaceElementIndex _sei) + { + const netgen::Element2d & el = mesh[_sei]; + sei = _sei; + index = el.GetIndex(); + np = el.GetNP(); + for (int k : Range(1, np+1)) { + auto & pnt = points[k-1];; + pnt.num = el.PNum(k); + pnt.trignum = el.GeomInfoPi(k).trignum; + pnt.u = el.GeomInfoPi(k).u; + pnt.v = el.GeomInfoPi(k).v; + } + /** otherwise, we use uninitialized values **/ + for (int k : Range(np, ELEMENT2D_MAXPOINTS)) { + points[k].num = -1; + points[k].trignum = -1; + points[k].u = -1; + points[k].v = -1; + } + } + void Unpack (netgen::Element2d & el) const { + el.SetIndex(index); + for (int k : Range(1, np + 1)) { + auto & pnt = points[k-1]; + el.PNum(k) = pnt.num; + el.GeomInfoPi(k).trignum = pnt.trignum; + el.GeomInfoPi(k).u = pnt.u; + el.GeomInfoPi(k).v = pnt.v; + } + } + SelPackage & operator = (const SelPackage & other) { + sei = other.sei; + index = other.index; + np = other.np; + for (int k : Range(ELEMENT2D_MAXPOINTS)) + { points[k] = other.points[k]; } + return *this; + } + }; // class SelPackage + + template<> struct MPI_typetrait { + static MPI_Datatype MPIType () { + static MPI_Datatype MPI_T = 0; + if (!MPI_T) + { + int block_len[2] = { 3, ELEMENT2D_MAXPOINTS }; + MPI_Aint displs[3] = { 0, 3*sizeof(int) }; + MPI_Datatype types[2] = { MPI_INT, GetMPIType() }; + MPI_Type_create_struct(2, block_len, displs, types, &MPI_T); + MPI_Type_commit(&MPI_T); + } + return MPI_T; + } + }; // MPI_typetrait + +} // namespace ngcore + +namespace netgen +{ /* template <> inline MPI_Datatype MyGetMPIType ( ) @@ -551,24 +653,14 @@ namespace netgen }; Array nlocsel(ntasks), bufsize(ntasks); nlocsel = 0; - bufsize = 1; + bufsize = 0; iterate_sels([&](SurfaceElementIndex sei, const Element2d & sel, int dest){ nlocsel[dest]++; - bufsize[dest] += 4 + 2*sel.GetNP(); + bufsize[dest]++; }); - DynamicTable selbuf(bufsize); - for (int dest = 1; dest < ntasks; dest++ ) - selbuf.Add (dest, nlocsel[dest]); + DynamicTable selbuf(bufsize); iterate_sels([&](SurfaceElementIndex sei, const auto & sel, int dest) { - selbuf.Add (dest, sei); - selbuf.Add (dest, sel.GetIndex()); - // selbuf.Add (dest, 0); - selbuf.Add (dest, sel.GetNP()); - for ( int ii = 1; ii <= sel.GetNP(); ii++) - { - selbuf.Add (dest, sel.PNum(ii)); - selbuf.Add (dest, sel.GeomInfoPi(ii).trignum); - } + selbuf.Add (dest, SelPackage(*this, sei)); }); // distribute sel data for (int dest = 1; dest < ntasks; dest++) @@ -953,33 +1045,25 @@ namespace netgen { NgProfiler::RegionTimer reg(timer_sels); - Array selbuf; + Array selbuf; comm.Recv ( selbuf, 0, MPI_TAG_MESH+4); - int ii = 0; - int sel = 0; - - int nlocsel = selbuf[ii++]; + int nlocsel = selbuf.Size(); paralleltop -> SetNSE ( nlocsel ); - while (ii < selbuf.Size()-1) - { - int globsel = selbuf[ii++]; - int faceind = selbuf[ii++]; - //bool isghost = selbuf[ii++]; - int nep = selbuf[ii++]; - Element2d tri(nep); - tri.SetIndex(faceind); - for(int j = 1; j <= nep; j++) - { - tri.PNum(j) = glob2loc_vert_ht.Get (selbuf[ii++]); - tri.GeomInfoPi(j).trignum = selbuf[ii++]; - } - paralleltop->SetLoc2Glob_SurfEl ( sel+1, globsel ); - AddSurfaceElement (tri); - sel ++; - } + int sel = 0; + for (auto k : Range(selbuf)) { + auto & pack = selbuf[k]; + Element2d el(pack.np); + pack.Unpack(el); + /** map global point numbers to local ones **/ + for (int k : Range(1, 1+el.GetNP())) + { el.PNum(k) = glob2loc_vert_ht.Get(el.PNum(k)); } + paralleltop->SetLoc2Glob_SurfEl (sel+1, pack.sei); + AddSurfaceElement (el); + sel++; + } } From 0256ce1efc70bc5374a4fe2ae22a2c0e92a2e312 Mon Sep 17 00:00:00 2001 From: Lukas Date: Mon, 8 Feb 2021 12:05:27 +0100 Subject: [PATCH 328/384] also send 0d elements when distributing mesh --- libsrc/meshing/parallelmesh.cpp | 75 +++++++++++++++++++++++++++++---- 1 file changed, 67 insertions(+), 8 deletions(-) diff --git a/libsrc/meshing/parallelmesh.cpp b/libsrc/meshing/parallelmesh.cpp index e2f9cbdc..76c8dabb 100644 --- a/libsrc/meshing/parallelmesh.cpp +++ b/libsrc/meshing/parallelmesh.cpp @@ -133,6 +133,33 @@ namespace ngcore } }; // MPI_typetrait + + class PointElPackage + { + public: + netgen::PointIndex pnum; + int index; + PointElPackage () { pnum = -1; index = -1; } + PointElPackage (const netgen::Element0d & el) + { pnum = el.pnum; index = el.index; } + }; // class PointElPackage + + template<> struct MPI_typetrait { + static MPI_Datatype MPIType () { + static MPI_Datatype MPI_T = 0; + if (!MPI_T) + { + int block_len[2] = { 1, 1 }; + MPI_Aint displs[3] = { 0, sizeof(netgen::PointIndex) }; + MPI_Datatype types[2] = { GetMPIType(), MPI_INT }; + MPI_Type_create_struct(2, block_len, displs, types, &MPI_T); + MPI_Type_commit(&MPI_T); + } + return MPI_T; + } + }; // MPI_typetrait + + } // namespace ngcore namespace netgen @@ -181,7 +208,6 @@ namespace netgen void Mesh :: SendMesh () const { - Array sendrequests; NgMPI_Comm comm = GetCommunicator(); int id = comm.Rank(); @@ -190,6 +216,8 @@ namespace netgen int dim = GetDimension(); comm.Bcast(dim); + Array sendrequests(8*(ntasks-1)); + sendrequests.SetSize0(); // If the topology is not already updated, we do not need to // build edges/faces. @@ -818,6 +846,27 @@ namespace netgen for (int dest = 1; dest < ntasks; dest++) sendrequests.Append (comm.ISend(segm_buf[dest], dest, MPI_TAG_MESH+5)); + /** Point-Elements **/ + PrintMessage ( 3, "Point-Elements ..."); + + auto iterate_zdes = [&](auto f) { + for (auto k : Range(pointelements)) { + auto & el = pointelements[k]; + PointElPackage pack(el); + auto dests = procs_of_vert[el.pnum]; + for (auto dest : dests) + { f(pack, dest); } + } + }; + + bufsize = 0; + iterate_zdes([&](const auto & pack, auto dest) { bufsize[dest]++; }); + DynamicTable zde_buf(bufsize); // zero dim elements + iterate_zdes([&](const auto & pack, auto dest) { zde_buf.Add(dest, pack); }); + + for (int dest = 1; dest < ntasks; dest++) + { sendrequests.Append (comm.ISend(zde_buf[dest], dest, MPI_TAG_MESH+6)); } + PrintMessage ( 3, "now wait ..."); MyMPI_WaitAll (sendrequests); @@ -841,7 +890,7 @@ namespace netgen nnames[3] = GetNCD3Names(); int tot_nn = nnames[0] + nnames[1] + nnames[2] + nnames[3]; for( int k = 1; k < ntasks; k++) - sendrequests[k] = comm.ISend(nnames, k, MPI_TAG_MESH+6); + sendrequests[k] = comm.ISend(nnames, k, MPI_TAG_MESH+7); // (void) MPI_Isend(nnames, 4, MPI_INT, k, MPI_TAG_MESH+6, comm, &sendrequests[k]); auto iterate_names = [&](auto func) { for (int k = 0; k < nnames[0]; k++) func(materials[k]); @@ -854,7 +903,7 @@ namespace netgen tot_nn = 0; iterate_names([&](auto ptr) { name_sizes[tot_nn++] = (ptr==NULL) ? 0 : ptr->size(); }); for( int k = 1; k < ntasks; k++) - (void) MPI_Isend(&name_sizes[0], tot_nn, MPI_INT, k, MPI_TAG_MESH+6, comm, &sendrequests[ntasks+k]); + (void) MPI_Isend(&name_sizes[0], tot_nn, MPI_INT, k, MPI_TAG_MESH+7, comm, &sendrequests[ntasks+k]); // names int strs = 0; iterate_names([&](auto ptr) { strs += (ptr==NULL) ? 0 : ptr->size(); }); @@ -866,7 +915,7 @@ namespace netgen for (int j=0; j < name.size(); j++) compiled_names[strs++] = name[j]; }); for( int k = 1; k < ntasks; k++) - (void) MPI_Isend(&(compiled_names[0]), strs, MPI_CHAR, k, MPI_TAG_MESH+6, comm, &sendrequests[2*ntasks+k]); + (void) MPI_Isend(&(compiled_names[0]), strs, MPI_CHAR, k, MPI_TAG_MESH+7, comm, &sendrequests[2*ntasks+k]); PrintMessage ( 3, "wait for names"); @@ -1109,16 +1158,26 @@ namespace netgen AddSegment (seg); segi++; } - } } + { /** 0d-Elements **/ + Array zdes; + comm.Recv ( zdes, 0, MPI_TAG_MESH+6); + pointelements.SetSize(zdes.Size()); + for (auto k : Range(pointelements)) { + auto & el = pointelements[k]; + el.pnum = glob2loc_vert_ht.Get(zdes[k].pnum); + el.index = zdes[k].index; + } + } + // paralleltop -> SetNV_Loc2Glob (0); paralleltop -> EnumeratePointsGlobally(); /** Recv bc-names **/ ArrayMem nnames{0,0,0,0}; // MPI_Recv(nnames, 4, MPI_INT, 0, MPI_TAG_MESH+6, comm, MPI_STATUS_IGNORE); - comm.Recv(nnames, 0, MPI_TAG_MESH+6); + comm.Recv(nnames, 0, MPI_TAG_MESH+7); // cout << "nnames = " << FlatArray(nnames) << endl; materials.SetSize(nnames[0]); bcnames.SetSize(nnames[1]); @@ -1127,12 +1186,12 @@ namespace netgen int tot_nn = nnames[0] + nnames[1] + nnames[2] + nnames[3]; NgArray name_sizes(tot_nn); - MPI_Recv(&name_sizes[0], tot_nn, MPI_INT, 0, MPI_TAG_MESH+6, comm, MPI_STATUS_IGNORE); + MPI_Recv(&name_sizes[0], tot_nn, MPI_INT, 0, MPI_TAG_MESH+7, comm, MPI_STATUS_IGNORE); int tot_size = 0; for (int k = 0; k < tot_nn; k++) tot_size += name_sizes[k]; NgArray compiled_names(tot_size); - MPI_Recv(&(compiled_names[0]), tot_size, MPI_CHAR, 0, MPI_TAG_MESH+6, comm, MPI_STATUS_IGNORE); + MPI_Recv(&(compiled_names[0]), tot_size, MPI_CHAR, 0, MPI_TAG_MESH+7, comm, MPI_STATUS_IGNORE); tot_nn = tot_size = 0; auto write_names = [&] (auto & array) { From 0c2430f3dce24fdb530d2ada338fe928589f73c4 Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Mon, 8 Feb 2021 15:44:15 +0100 Subject: [PATCH 329/384] add std::any symboltable to Flags to store arbitrary objects --- libsrc/core/flags.cpp | 23 ++++++++++++++++++++++- libsrc/core/flags.hpp | 7 +++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/libsrc/core/flags.cpp b/libsrc/core/flags.cpp index cdf5a7e7..e3d845cf 100644 --- a/libsrc/core/flags.cpp +++ b/libsrc/core/flags.cpp @@ -51,6 +51,10 @@ namespace ngcore auto lflags = flags.GetFlagsFlag (i, name); SetFlag (name, lflags); } + for(auto i : Range(flags.anyflags.Size())) + { + SetFlag(flags.anyflags.GetName(i), flags.anyflags[i]); + } } Flags :: Flags (Flags && flags) @@ -178,7 +182,11 @@ namespace ngcore return *this; } - + Flags & Flags :: SetFlag (const string & name, const std::any & val) + { + anyflags.Set(name, val); + return *this; + } string Flags :: GetStringFlag (const string & name, const char * def) const { @@ -279,6 +287,14 @@ namespace ngcore } } + const std::any& Flags:: GetAnyFlag(const std::string& name) const + { + if(anyflags.Used(name)) + return anyflags[name]; + static std::any empty; + return empty; + } + bool Flags :: StringFlagDefined (const string & name) const { return strflags.Used (name); @@ -304,6 +320,11 @@ namespace ngcore return numlistflags.Used (name); } + bool Flags :: AnyFlagDefined (const string& name) const + { + return anyflags.Used(name); + } + void Flags :: SaveFlags (ostream & str) const { for (int i = 0; i < strflags.Size(); i++) diff --git a/libsrc/core/flags.hpp b/libsrc/core/flags.hpp index ea4a093c..cd4b8272 100644 --- a/libsrc/core/flags.hpp +++ b/libsrc/core/flags.hpp @@ -11,6 +11,7 @@ #include #include #include +#include #include "array.hpp" #include "symboltable.hpp" @@ -38,6 +39,8 @@ namespace ngcore SymbolTable>> numlistflags; /// flags list flags SymbolTable flaglistflags; + /// any object can be stored as a flag + SymbolTable anyflags; public: /// no flags Flags (); @@ -94,6 +97,8 @@ namespace ngcore Flags & SetFlag (const std::string & name, const Array & val); /// Sets double array flag Flags & SetFlag (const std::string & name, const Array & val); + /// Sets any flag + Flags & SetFlag(const std::string& name, const std::any& val); Flags SetFlag (const char * name, bool b = true) &&; @@ -135,6 +140,7 @@ namespace ngcore const Array & GetNumListFlag (const std::string & name) const; /// Returns flag list flag, empty flag if not exist const Flags & GetFlagsFlag (const std::string & name) const; + const std::any& GetAnyFlag (const std::string& name) const; /// Test, if string flag is defined @@ -147,6 +153,7 @@ namespace ngcore bool StringListFlagDefined (const std::string & name) const; /// Test, if num list flag is defined bool NumListFlagDefined (const std::string & name) const; + bool AnyFlagDefined (const std::string& name) const; /// number of string flags int GetNStringFlags () const { return strflags.Size(); } From b03528e9441b6f2e87571070f2e1f350d1722e27 Mon Sep 17 00:00:00 2001 From: Joachim Schoeberl Date: Tue, 9 Feb 2021 21:14:26 +0100 Subject: [PATCH 330/384] third parent edge --- libsrc/meshing/topology.cpp | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/libsrc/meshing/topology.cpp b/libsrc/meshing/topology.cpp index 09a73f3c..e2446f87 100644 --- a/libsrc/meshing/topology.cpp +++ b/libsrc/meshing/topology.cpp @@ -707,15 +707,15 @@ namespace netgen ma->GetParentNodes (i2[0], pa1); ma->GetParentNodes (i2[1], pa2); */ - auto i2 = edge2vert[i]; + auto i2 = edge2vert[i]; // 2 vertices of edge if (i2[0] > mesh->mlbetweennodes.Size()+PointIndex::BASE || i2[1] > mesh->mlbetweennodes.Size()+PointIndex::BASE) continue; // cout << "i2 = " << i2 << endl; - auto pa1 = mesh->mlbetweennodes[i2[0]]; - auto pa2 = mesh->mlbetweennodes[i2[1]]; + auto pa1 = mesh->mlbetweennodes[i2[0]]; // two parent vertices of v0 + auto pa2 = mesh->mlbetweennodes[i2[1]]; // two parent vertices of v1 // cout << "pa1 = " << pa1 << endl; // cout << "pa2 = " << pa2 << endl; @@ -759,28 +759,35 @@ namespace netgen // edge is splitting edge in middle of triangle: for (int j = 1; j <= 2; j++) { - INT<2> paedge1, paedge2; + INT<2> paedge1, paedge2, paedge3; + int orient_inner = 0; if (j == 1) { paedge1 = INT<2> (pa1[0], i2[1]); paedge2 = INT<2> (pa1[1], i2[1]); + paedge3 = INT<2> (pa1[0], pa1[1]); + orient_inner = 0; } else { paedge1 = INT<2> (pa2[0], i2[0]); paedge2 = INT<2> (pa2[1], i2[0]); + paedge3 = INT<2> (pa2[0], pa2[1]); + orient_inner = 1; } if (paedge1[0] > paedge1[1]) Swap (paedge1[0], paedge1[1]); if (paedge2[0] > paedge2[1]) Swap (paedge2[0], paedge2[1]); + if (paedge3[0] > paedge3[1]) + Swap (paedge3[0], paedge3[1]); // cout << "paedge1 = " << paedge1 << ", paedge2 = " << paedge2 << endl; // if first vertex number is -1, then don't try to find entry in node2edge hash table if ( paedge1[0] == PointIndex::BASE-1 || paedge2[0] == PointIndex::BASE-1 ) continue; - int paedgenr1=-1, paedgenr2=-1, orient1 = 0, orient2 = 0; + int paedgenr1=-1, paedgenr2=-1, paedgenr3=-1, orient1 = 0, orient2 = 0; for (int ednr : vert2edge[paedge1[0]]) if (auto ic2 = edge2vert[ednr]; ic2[1] == paedge1[1]) { @@ -797,8 +804,16 @@ namespace netgen orient2 = (paedge2[0] == i2[0] || paedge2[1] == i2[1]) ? 1 : 0; // cout << "orient2 = " << orient2 << endl; } + + for (int ednr : vert2edge[paedge3[0]]) + if (auto ic2 = edge2vert[ednr]; ic2[1] == paedge3[1]) + { + paedgenr3 = ednr; + // cout << "ednr = " << ednr << ", i2 = " << i2 << endl; + } + if (paedgenr1 != -1 && paedgenr2 != -1) - parent_edges[i] = { orient1+2*orient2, { paedgenr1, paedgenr2, -1 } }; + parent_edges[i] = { orient1+2*orient2+4*orient_inner, { paedgenr1, paedgenr2, paedgenr3 } }; } From 2e69b39339b3b91bea3513335fa034ca46a61cbf Mon Sep 17 00:00:00 2001 From: Joachim Schoeberl Date: Wed, 10 Feb 2021 19:39:52 +0100 Subject: [PATCH 331/384] cleanup parent_edges --- libsrc/meshing/topology.cpp | 93 ++++++++++++------------------------- 1 file changed, 30 insertions(+), 63 deletions(-) diff --git a/libsrc/meshing/topology.cpp b/libsrc/meshing/topology.cpp index e2446f87..f128c10e 100644 --- a/libsrc/meshing/topology.cpp +++ b/libsrc/meshing/topology.cpp @@ -683,74 +683,49 @@ namespace netgen { static Timer t("build_hierarchy"); RegionTimer reg(t); cnt = 0; - for (size_t i = 0; i < edge2vert.Size(); i++) - cnt[edge2vert[i][0]]++; + for (auto verts : edge2vert) cnt[verts[0]]++; TABLE vert2edge (cnt); - for (size_t i = 0; i < edge2vert.Size(); i++) + for (auto i : edge2vert.Range()) vert2edge.AddSave (edge2vert[i][0], i); - + // build edge hierarchy: parent_edges.SetSize (ned); parent_edges = { -1, { -1, -1, -1 } }; - /* - cout << "mlbetween = " << mesh->mlbetweennodes.Size() << endl; - cout << "mlbetween = " << endl << mesh->mlbetweennodes << endl; - cout << "v2e = " << endl << vert2edge << endl; - cout << "e2v = " << endl << edge2vert << endl; - cout << "ned = " << ned << endl; - */ + for (size_t i = 0; i < ned; i++) { - // cout << " ref edge " << i << "/" << ned << endl; - /* - int pa1[2], pa2[2]; - ma->GetParentNodes (i2[0], pa1); - ma->GetParentNodes (i2[1], pa2); - */ - auto i2 = edge2vert[i]; // 2 vertices of edge + auto verts = edge2vert[i]; // 2 vertices of edge - if (i2[0] > mesh->mlbetweennodes.Size()+PointIndex::BASE || - i2[1] > mesh->mlbetweennodes.Size()+PointIndex::BASE) + if (verts[0] > mesh->mlbetweennodes.Size()+PointIndex::BASE || + verts[1] > mesh->mlbetweennodes.Size()+PointIndex::BASE) continue; - - // cout << "i2 = " << i2 << endl; - auto pa1 = mesh->mlbetweennodes[i2[0]]; // two parent vertices of v0 - auto pa2 = mesh->mlbetweennodes[i2[1]]; // two parent vertices of v1 - - // cout << "pa1 = " << pa1 << endl; - // cout << "pa2 = " << pa2 << endl; - //if (pa1[0] == -1 && pa2[0] == -1) - // continue; + + auto pa0 = mesh->mlbetweennodes[verts[0]]; // two parent vertices of v0 + auto pa1 = mesh->mlbetweennodes[verts[1]]; // two parent vertices of v1 // both vertices are on coarsest mesh - if (!pa1[0].IsValid() && !pa2[0].IsValid()) + if (!pa0[0].IsValid() && !pa1[0].IsValid()) continue; - int issplitedge = 0; - if (pa1[0] == i2[1] || pa1[1] == i2[1]) + if (pa0[0] == verts[1] || pa0[1] == verts[1]) issplitedge = 1; - if (pa2[0] == i2[0] || pa2[1] == i2[0]) + if (pa1[0] == verts[0] || pa1[1] == verts[0]) issplitedge = 2; if (issplitedge) { // cout << "split edge " << endl; // edge is obtained by splitting one edge into two parts: - INT<2> paedge; - if (issplitedge == 1) - paedge = INT<2> (pa1[0], pa1[1]); - else - paedge = INT<2> (pa2[0], pa2[1]); - + auto paedge = issplitedge == 1 ? pa0 : pa1; + if (paedge[0] > paedge[1]) Swap (paedge[0], paedge[1]); - + for (int ednr : vert2edge[paedge[0]]) - if (auto ic2 = edge2vert[ednr]; ic2[1] == paedge[1]) + if (auto cverts = edge2vert[ednr]; cverts[1] == paedge[1]) { - // cout << "matching: " << ednr << endl; - int orient = (paedge[0] == i2[0] || paedge[1] == i2[1]) ? 1 : 0; + int orient = (paedge[0] == verts[0] || paedge[1] == verts[1]) ? 1 : 0; parent_edges[i] = { orient, { ednr, -1, -1 } }; } } @@ -763,16 +738,16 @@ namespace netgen int orient_inner = 0; if (j == 1) { - paedge1 = INT<2> (pa1[0], i2[1]); - paedge2 = INT<2> (pa1[1], i2[1]); - paedge3 = INT<2> (pa1[0], pa1[1]); + paedge1 = INT<2> (pa0[0], verts[1]); + paedge2 = INT<2> (pa0[1], verts[1]); + paedge3 = INT<2> (pa0[0], pa0[1]); orient_inner = 0; } else { - paedge1 = INT<2> (pa2[0], i2[0]); - paedge2 = INT<2> (pa2[1], i2[0]); - paedge3 = INT<2> (pa2[0], pa2[1]); + paedge1 = INT<2> (pa1[0], verts[0]); + paedge2 = INT<2> (pa1[1], verts[0]); + paedge3 = INT<2> (pa1[0], pa1[1]); orient_inner = 1; } if (paedge1[0] > paedge1[1]) @@ -782,35 +757,27 @@ namespace netgen if (paedge3[0] > paedge3[1]) Swap (paedge3[0], paedge3[1]); - // cout << "paedge1 = " << paedge1 << ", paedge2 = " << paedge2 << endl; // if first vertex number is -1, then don't try to find entry in node2edge hash table if ( paedge1[0] == PointIndex::BASE-1 || paedge2[0] == PointIndex::BASE-1 ) continue; int paedgenr1=-1, paedgenr2=-1, paedgenr3=-1, orient1 = 0, orient2 = 0; for (int ednr : vert2edge[paedge1[0]]) - if (auto ic2 = edge2vert[ednr]; ic2[1] == paedge1[1]) + if (auto cverts = edge2vert[ednr]; cverts[1] == paedge1[1]) { paedgenr1 = ednr; - // cout << "ednr = " << ednr << ", i2 = " << i2 << endl; - orient1 = (paedge1[0] == i2[0] || paedge1[1] == i2[1]) ? 1 : 0; - // cout << "orient1 = " << orient1 << endl; + orient1 = (paedge1[0] == verts[0] || paedge1[1] == verts[1]) ? 1 : 0; } for (int ednr : vert2edge[paedge2[0]]) - if (auto ic2 = edge2vert[ednr]; ic2[1] == paedge2[1]) + if (auto cverts = edge2vert[ednr]; cverts[1] == paedge2[1]) { paedgenr2 = ednr; - // cout << "ednr = " << ednr << ", i2 = " << i2 << endl; - orient2 = (paedge2[0] == i2[0] || paedge2[1] == i2[1]) ? 1 : 0; - // cout << "orient2 = " << orient2 << endl; + orient2 = (paedge2[0] == verts[0] || paedge2[1] == verts[1]) ? 1 : 0; } for (int ednr : vert2edge[paedge3[0]]) - if (auto ic2 = edge2vert[ednr]; ic2[1] == paedge3[1]) - { - paedgenr3 = ednr; - // cout << "ednr = " << ednr << ", i2 = " << i2 << endl; - } + if (auto cverts = edge2vert[ednr]; cverts[1] == paedge3[1]) + paedgenr3 = ednr; if (paedgenr1 != -1 && paedgenr2 != -1) parent_edges[i] = { orient1+2*orient2+4*orient_inner, { paedgenr1, paedgenr2, paedgenr3 } }; From 87e472b6fc638cea3663b8b64803af14174c1697 Mon Sep 17 00:00:00 2001 From: Joachim Schoeberl Date: Wed, 17 Feb 2021 14:54:14 +0100 Subject: [PATCH 332/384] start face-hierarchy in Netgen --- libsrc/core/hashtable.hpp | 7 +++++ libsrc/meshing/topology.cpp | 59 +++++++++++++++++++++++++++++++++++-- 2 files changed, 64 insertions(+), 2 deletions(-) diff --git a/libsrc/core/hashtable.hpp b/libsrc/core/hashtable.hpp index 00739ffb..29f35858 100644 --- a/libsrc/core/hashtable.hpp +++ b/libsrc/core/hashtable.hpp @@ -174,6 +174,13 @@ namespace ngcore { return MakeTupleFromInt()(*this); } + + bool Contains (T val) + { + for (int j = 0; j < N; j++) + if (i[j] == val) return true; + return false; + } }; /// sort 2 integers diff --git a/libsrc/meshing/topology.cpp b/libsrc/meshing/topology.cpp index f128c10e..fa81a64f 100644 --- a/libsrc/meshing/topology.cpp +++ b/libsrc/meshing/topology.cpp @@ -696,8 +696,8 @@ namespace netgen { auto verts = edge2vert[i]; // 2 vertices of edge - if (verts[0] > mesh->mlbetweennodes.Size()+PointIndex::BASE || - verts[1] > mesh->mlbetweennodes.Size()+PointIndex::BASE) + if (verts[0] >= mesh->mlbetweennodes.Size()+PointIndex::BASE || + verts[1] >= mesh->mlbetweennodes.Size()+PointIndex::BASE) continue; auto pa0 = mesh->mlbetweennodes[verts[0]]; // two parent vertices of v0 @@ -1436,6 +1436,61 @@ namespace netgen cout << cnt_err << " elements are not matching !!!" << endl; } // NgProfiler::StopTimer (timer2c); + + + if (build_hierarchy) + { + // tets only + + ngcore::ClosedHashTable, int> v2f(nv); + for (auto i : Range(face2vert)) + { + auto face = face2vert[i]; + INT<3> f3(face[0], face[1], face[2]); + f3.Sort(); + v2f[f3] = i; + } + + cout << "v2f:" << endl << v2f << endl; + + parent_faces.SetSize (nfa); + parent_faces = { -1, { -1, -1, -1, -1 } }; + + for (auto i : Range(nfa)) + { + INT<3,PointIndex> f3(face2vert[i][0], face2vert[i][1], face2vert[i][2]); + PointIndex vmax = Max(f3); + if (vmax >= mesh->mlbetweennodes.Size()+PointIndex::BASE) + continue; + + auto parents = mesh->mlbetweennodes[vmax]; + + // is face part of one parent face (boundary-face) ? + for (int j = 0; j < 2; j++) + { + if (f3.Contains(parents[j])) + { + PointIndex v0 = parents[j]; + PointIndex v1 = parents[1-j]; + + // the third one, on the tip + PointIndex v2 = f3[0]+f3[1]+f3[2] - v0 - v1; + + int classnr = 0; + if (v0 > v1) { Swap (v0, v1); classnr += 1; } + if (v1 > v2) { Swap (v1, v2); classnr += 2; } + if (v0 > v1) { Swap (v0, v1); classnr += 4; } + + INT<3> parentverts(v0, v1, v2); + int pafacenr = v2f[parentverts]; + cout << "parent-face = " << pafacenr << endl; + parent_faces[i] = { classnr, { pafacenr, -1, -1, -1 } }; + } + } + } + + } + } From e9e3d52b45145cf34910e39fab0bfa504e0d1be0 Mon Sep 17 00:00:00 2001 From: Joachim Schoeberl Date: Wed, 17 Feb 2021 23:32:15 +0100 Subject: [PATCH 333/384] parent faces --- libsrc/include/nginterface_v2.hpp | 2 + libsrc/interface/nginterface_v2.cpp | 7 +++ libsrc/meshing/python_mesh.cpp | 9 ++- libsrc/meshing/topology.cpp | 87 +++++++++++++++++++---------- libsrc/meshing/topology.hpp | 17 +++--- 5 files changed, 84 insertions(+), 38 deletions(-) diff --git a/libsrc/include/nginterface_v2.hpp b/libsrc/include/nginterface_v2.hpp index 82074cfc..de18cf05 100644 --- a/libsrc/include/nginterface_v2.hpp +++ b/libsrc/include/nginterface_v2.hpp @@ -345,6 +345,8 @@ namespace netgen void Curve (int order); int GetCurveOrder (); + void EnableTable (string name, bool set); + void Refine (NG_REFINEMENT_TYPE reftype, void (*taskmanager)(function) = &DummyTaskManager2, void (*tracer)(string, bool) = &DummyTracer2); diff --git a/libsrc/interface/nginterface_v2.cpp b/libsrc/interface/nginterface_v2.cpp index cca8b3a4..0f3f48a9 100644 --- a/libsrc/interface/nginterface_v2.cpp +++ b/libsrc/interface/nginterface_v2.cpp @@ -1137,6 +1137,13 @@ namespace netgen return mesh->GetCurvedElements().GetOrder(); } + void Ngx_Mesh :: EnableTable (string name, bool set) + { + mesh->GetTopology().EnableTable (name, set); + } + + + template <> DLL_HEADER void Ngx_Mesh :: SetRefinementFlag<2> (size_t elnr, bool flag) { diff --git a/libsrc/meshing/python_mesh.cpp b/libsrc/meshing/python_mesh.cpp index 5c92d3dd..fd88061c 100644 --- a/libsrc/meshing/python_mesh.cpp +++ b/libsrc/meshing/python_mesh.cpp @@ -1129,15 +1129,20 @@ project_boundaries : Optional[str] = None .def ("EnableTable", [] (Mesh & self, string name, bool set) { + const_cast(self.GetTopology()).EnableTable(name, set); + /* if (name == "edges") const_cast(self.GetTopology()).SetBuildEdges(set); else if (name == "faces") const_cast(self.GetTopology()).SetBuildFaces(set); else if (name == "parentedges") - const_cast(self.GetTopology()).SetBuildHierarchy(set); + const_cast(self.GetTopology()).SetBuildParentEdges(set); + else if (name == "parentfaces") + const_cast(self.GetTopology()).SetBuildParentFaces(set); else throw Exception ("noting known about table "+name +"\n" - "knwon are 'edges', 'faces', 'parentedges'"); + "knwon are 'edges', 'faces', 'parentedges', 'parentfaces'"); + */ }, py::arg("name"), py::arg("set")=true) diff --git a/libsrc/meshing/topology.cpp b/libsrc/meshing/topology.cpp index fa81a64f..49a4747c 100644 --- a/libsrc/meshing/topology.cpp +++ b/libsrc/meshing/topology.cpp @@ -55,6 +55,24 @@ namespace netgen bool MeshTopology :: NeedsUpdate() const { return (timestamp <= mesh->GetTimeStamp()); } + + void MeshTopology :: EnableTable (string name, bool set) + { + if (name == "edges") + SetBuildEdges(set); + else if (name == "faces") + SetBuildFaces(set); + else if (name == "parentedges") + SetBuildParentEdges(set); + else if (name == "parentfaces") + SetBuildParentFaces(set); + else + throw Exception ("noting known about table "+name +"\n" + "knwon are 'edges', 'faces', 'parentedges', 'parentfaces'"); + } + + + template void LoopOverEdges (const Mesh & mesh, MeshTopology & top, PointIndex v, FUNC func) @@ -679,7 +697,7 @@ namespace netgen } ); - if (build_hierarchy) + if (build_parent_edges) { static Timer t("build_hierarchy"); RegionTimer reg(t); cnt = 0; @@ -1438,10 +1456,12 @@ namespace netgen // NgProfiler::StopTimer (timer2c); - if (build_hierarchy) + if (build_parent_faces) { // tets only - + cout << "build face hierarchy:" << endl; + cout << "f2v = " << face2vert << endl; + ngcore::ClosedHashTable, int> v2f(nv); for (auto i : Range(face2vert)) { @@ -1459,38 +1479,49 @@ namespace netgen for (auto i : Range(nfa)) { INT<3,PointIndex> f3(face2vert[i][0], face2vert[i][1], face2vert[i][2]); - PointIndex vmax = Max(f3); - if (vmax >= mesh->mlbetweennodes.Size()+PointIndex::BASE) - continue; - - auto parents = mesh->mlbetweennodes[vmax]; - // is face part of one parent face (boundary-face) ? - for (int j = 0; j < 2; j++) + // find a vertex, such that one of its parent is a trig vertex + + for (int k = 0; k < 3; k++) { - if (f3.Contains(parents[j])) + PointIndex v3 = f3[k]; + + if (v3 >= mesh->mlbetweennodes.Size()+PointIndex::BASE) + continue; + auto parents = mesh->mlbetweennodes[v3]; + + // is face part of one parent face (boundary-face) ? + for (int j = 0; j < 2; j++) { - PointIndex v0 = parents[j]; - PointIndex v1 = parents[1-j]; - - // the third one, on the tip - PointIndex v2 = f3[0]+f3[1]+f3[2] - v0 - v1; - - int classnr = 0; - if (v0 > v1) { Swap (v0, v1); classnr += 1; } - if (v1 > v2) { Swap (v1, v2); classnr += 2; } - if (v0 > v1) { Swap (v0, v1); classnr += 4; } - - INT<3> parentverts(v0, v1, v2); - int pafacenr = v2f[parentverts]; - cout << "parent-face = " << pafacenr << endl; - parent_faces[i] = { classnr, { pafacenr, -1, -1, -1 } }; + if (f3.Contains(parents[j])) + { + PointIndex v0 = parents[j]; + PointIndex v1 = parents[1-j]; + + // the third one, on the tip + PointIndex v2 = f3[0]+f3[1]+f3[2] - v0 - v3; + + INT<3> parentverts(v0, v1, v2); + parentverts.Sort(); + + + int classnr = 0; + if (v2 > v3) { Swap (v2, v3); classnr += 1; } + if (v0 > v1) { Swap (v0, v1); classnr += 2; } + if (v1 > v2) { Swap (v1, v2); classnr += 4; } + if (v0 > v1) { Swap (v0, v1); classnr += 8; } + + if (v2f.Used(parentverts)) + { + int pafacenr = v2f[parentverts]; + cout << "parent-face = " << pafacenr << endl; + parent_faces[i] = { classnr, { pafacenr, -1, -1, -1 } }; + } + } } } } - } - } diff --git a/libsrc/meshing/topology.hpp b/libsrc/meshing/topology.hpp index 2a9c3c9b..57205600 100644 --- a/libsrc/meshing/topology.hpp +++ b/libsrc/meshing/topology.hpp @@ -45,7 +45,8 @@ class MeshTopology const Mesh * mesh; bool buildedges; bool buildfaces; - bool build_hierarchy = false; // may be changed to default = false + bool build_parent_edges = false; // may be changed to default = false + bool build_parent_faces = false; // may be changed to default = false NgArray edge2vert; NgArray face2vert; @@ -80,14 +81,14 @@ public: { buildedges = be; } void SetBuildFaces (bool bf) { buildfaces = bf; } - void SetBuildHierarchy (bool bh) { build_hierarchy = bh; } + void SetBuildParentEdges (bool bh) { build_parent_edges = bh; } + void SetBuildParentFaces (bool bh) { build_parent_faces = bh; } - bool HasEdges () const - { return buildedges; } - bool HasFaces () const - { return buildfaces; } - bool HasParentEdges () const - { return build_hierarchy; } + void EnableTable (string name, bool set); + + bool HasEdges () const { return buildedges; } + bool HasFaces () const { return buildfaces; } + bool HasParentEdges () const { return build_parent_edges; } void Update(NgTaskManager tm = &DummyTaskManager, NgTracer tracer = &DummyTracer); bool NeedsUpdate() const; From c7666ae99f1008d3c4e7d9406654816417c744f3 Mon Sep 17 00:00:00 2001 From: Joachim Schoeberl Date: Thu, 18 Feb 2021 08:43:22 +0100 Subject: [PATCH 334/384] classify bisect face (thx Guosheng) --- libsrc/meshing/topology.cpp | 100 +++++++++++++++++++++++++++++++++--- 1 file changed, 94 insertions(+), 6 deletions(-) diff --git a/libsrc/meshing/topology.cpp b/libsrc/meshing/topology.cpp index 49a4747c..701f09ba 100644 --- a/libsrc/meshing/topology.cpp +++ b/libsrc/meshing/topology.cpp @@ -1472,6 +1472,20 @@ namespace netgen } cout << "v2f:" << endl << v2f << endl; + + // build edge2vert hashtable + cout << "e2v = " << edge2vert << endl; + + ngcore::ClosedHashTable, int> v2e(nv); + for (auto i : Range(edge2vert)) + { + auto edge = edge2vert[i]; + INT<3> e2(edge[0], edge[1]); + e2.Sort(); + v2e[e2] = i; + } + + cout << "v2e:" << endl << v2e << endl; parent_faces.SetSize (nfa); parent_faces = { -1, { -1, -1, -1, -1 } }; @@ -1484,12 +1498,13 @@ namespace netgen for (int k = 0; k < 3; k++) { - PointIndex v3 = f3[k]; + PointIndex vb = f3[k]; // assume vb as the new bisect vert - if (v3 >= mesh->mlbetweennodes.Size()+PointIndex::BASE) + if (vb >= mesh->mlbetweennodes.Size()+PointIndex::BASE) continue; - auto parents = mesh->mlbetweennodes[v3]; - + auto parents = mesh->mlbetweennodes[vb]; + + bool issplit=false; // is face part of one parent face (boundary-face) ? for (int j = 0; j < 2; j++) { @@ -1499,14 +1514,14 @@ namespace netgen PointIndex v1 = parents[1-j]; // the third one, on the tip - PointIndex v2 = f3[0]+f3[1]+f3[2] - v0 - v3; + PointIndex v2 = f3[0]+f3[1]+f3[2] - v0 - vb; INT<3> parentverts(v0, v1, v2); parentverts.Sort(); int classnr = 0; - if (v2 > v3) { Swap (v2, v3); classnr += 1; } + if (v2 > vb) { Swap (v2, vb); classnr += 1; } if (v0 > v1) { Swap (v0, v1); classnr += 2; } if (v1 > v2) { Swap (v1, v2); classnr += 4; } if (v0 > v1) { Swap (v0, v1); classnr += 8; } @@ -1517,8 +1532,81 @@ namespace netgen cout << "parent-face = " << pafacenr << endl; parent_faces[i] = { classnr, { pafacenr, -1, -1, -1 } }; } + issplit=true; + break; } + } + // is face a new face (bisect-face) ? + if (!issplit){ + PointIndex v0 = parents[0]; + PointIndex v1 = parents[1]; + PointIndex v2 = f3[(k+1)%3]; + PointIndex v3 = f3[(k+2)%3]; + INT<3> parentedge1(v0, v2); + parentedge1.Sort(); + INT<3> parentedge2(v0, v3); + parentedge2.Sort(); + INT<3> parentedge3(v1, v2); + parentedge3.Sort(); + INT<3> parentedge4(v1, v3); + parentedge4.Sort(); + // if edges [v0,v2], [v0, v3], [v1,v2], [v1,v3] exists + // then vb is the bisecting edge + if (v2e.Used(parentedge1) && v2e.Used(parentedge2) + && v2e.Used(parentedge3) && v2e.Used(parentedge4) + ){ + int classnr; + if (k==2){// vb is the largest vert: 6 cases + // by default v0 < v1, v2 < v3 + if (v1 < v2) classnr = 0; + else if (v1 < v3 and v0 < v2) classnr = 1; + else if (v0 < v2) classnr = 2; + else if (v1 < v3) classnr = 3; + else if (v0 < v3) classnr = 4; + else classnr = 5; + }else if (k==1){// vb is the second largest vert: 3 cases + // by default v0 < v1, v3 < v2 + if (v1 < v3) classnr = 6; + else if (v0 < v3) classnr = 7; + else classnr = 8; + }else {// vb is the third largest vert: 1 case + // by default v0 < v1 < vb < v2 < v3 + classnr=9; + } + INT<3> parentverts1(v0, v2, v3); + parentverts1.Sort(); + INT<3> parentverts2(v1, v2, v3); + parentverts2.Sort(); + INT<3> parentverts3(v0, v1, v2); + parentverts3.Sort(); + INT<3> parentverts4(v0, v1, v3); + parentverts4.Sort(); + int pafacenr1=-1, pafacenr2=-1, pafacenr3=-1, pafacenr4=-1; + if (v2f.Used(parentverts1)) + { + pafacenr1 = v2f[parentverts1]; + cout << "parent-face1 = " << pafacenr1<< endl ; + } + if (v2f.Used(parentverts2)) + { + pafacenr2 = v2f[parentverts2]; + cout << "parent-face2 = " << pafacenr2<< endl ; + } + if (v2f.Used(parentverts3)) + { + pafacenr3 = v2f[parentverts3]; + cout << "parent-face3 = " << pafacenr3<< endl ; + } + if (v2f.Used(parentverts4)) + { + pafacenr4 = v2f[parentverts4]; + cout << "parent-face4 = " << pafacenr4<< endl ; + } + parent_faces[i] = { classnr, { pafacenr1, pafacenr2, pafacenr3, + pafacenr4} }; + break; } + } } } } From d1c9b4b24ffd0422221f380b52d91e560deba9b3 Mon Sep 17 00:00:00 2001 From: Joachim Schoeberl Date: Thu, 18 Feb 2021 09:28:09 +0100 Subject: [PATCH 335/384] no 'and' in C++ (but ok for gcc and clang ?) --- libsrc/meshing/topology.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/libsrc/meshing/topology.cpp b/libsrc/meshing/topology.cpp index 701f09ba..7502091a 100644 --- a/libsrc/meshing/topology.cpp +++ b/libsrc/meshing/topology.cpp @@ -879,12 +879,13 @@ namespace netgen } - + /* for (int i : Range(parent_edges)) { auto [info, nrs] = parent_edges[i]; - // cout << "edge " << i << " has " << info << ", nrs = " << nrs[0] << " " << nrs[1] << endl; + cout << "edge " << i << " has " << info << ", nrs = " << nrs[0] << " " << nrs[1] << endl; } + */ } } @@ -1559,7 +1560,7 @@ namespace netgen if (k==2){// vb is the largest vert: 6 cases // by default v0 < v1, v2 < v3 if (v1 < v2) classnr = 0; - else if (v1 < v3 and v0 < v2) classnr = 1; + else if (v1 < v3 && v0 < v2) classnr = 1; else if (v0 < v2) classnr = 2; else if (v1 < v3) classnr = 3; else if (v0 < v3) classnr = 4; From 979a695f62acf7dd70b87009743cb89b5bfe53cc Mon Sep 17 00:00:00 2001 From: Joachim Schoeberl Date: Thu, 18 Feb 2021 10:30:01 +0100 Subject: [PATCH 336/384] fixing warnings --- libsrc/core/archive.hpp | 4 ++-- libsrc/core/array.hpp | 6 +++--- libsrc/core/localheap.hpp | 6 +++--- libsrc/core/profiler.hpp | 12 ++++++------ libsrc/core/table.hpp | 2 +- libsrc/core/taskmanager.hpp | 4 ++-- libsrc/core/xbool.hpp | 4 ++-- 7 files changed, 19 insertions(+), 19 deletions(-) diff --git a/libsrc/core/archive.hpp b/libsrc/core/archive.hpp index d56e3f7f..3bab01f3 100644 --- a/libsrc/core/archive.hpp +++ b/libsrc/core/archive.hpp @@ -947,9 +947,9 @@ namespace ngcore template Archive& ApplyHash(T val) { - auto n = sizeof(T); + size_t n = sizeof(T); char* pval = (char*)&val; - for(int i = 0; i < n; i++) + for(size_t i = 0; i < n; i++) { h[offset++] ^= pval[i]; offset %= 8; diff --git a/libsrc/core/array.hpp b/libsrc/core/array.hpp index 752f6f64..d47e4b78 100644 --- a/libsrc/core/array.hpp +++ b/libsrc/core/array.hpp @@ -40,7 +40,7 @@ namespace ngcore }; template - ostream & operator<< (ostream & ost, Tuple tup) + ostream & operator<< (ostream & ost, Tuple /* tup */) { return ost; } @@ -1227,7 +1227,7 @@ namespace ngcore template - size_t ArraySize (Tuple tup) + size_t ArraySize (Tuple /* tup */) { return 0;} template @@ -1240,7 +1240,7 @@ namespace ngcore template - void StoreToArray (FlatArray a, Tuple tup) { ; } + void StoreToArray (FlatArray /* a */, Tuple /* tup */) { ; } template void StoreToArray (FlatArray a, Tuple tup) diff --git a/libsrc/core/localheap.hpp b/libsrc/core/localheap.hpp index 75de3c87..bc295e79 100644 --- a/libsrc/core/localheap.hpp +++ b/libsrc/core/localheap.hpp @@ -198,9 +198,9 @@ public: return reinterpret_cast (oldp); } - virtual void Delete(void* p) {} + virtual void Delete(void* /* p */) {} - virtual void ArrayDelete(void* p) {} + virtual void ArrayDelete(void* /* p */) {} private: /// #ifndef __CUDA_ARCH__ @@ -211,7 +211,7 @@ public: public: /// free memory (dummy function) - NETGEN_INLINE void Free (void * data) throw () + NETGEN_INLINE void Free (void * /* data */) throw () { ; } diff --git a/libsrc/core/profiler.hpp b/libsrc/core/profiler.hpp index 208b7a4e..d49b6543 100644 --- a/libsrc/core/profiler.hpp +++ b/libsrc/core/profiler.hpp @@ -438,21 +438,21 @@ namespace ngcore #else // NETGEN_TRACE_MEMORY public: MemoryTracer() {} - MemoryTracer( std::string name ) {} + MemoryTracer( std::string /* name */ ) {} template - MemoryTracer( std::string name, TRest & ... ) {} + MemoryTracer( std::string /* name */, TRest & ... ) {} - void Alloc(size_t size) const {} - void Free(size_t size) const {} + void Alloc(size_t /* size */) const {} + void Free(size_t /* size */) const {} void Swap(...) const {} int GetId() const { return 0; } template void Track(TRest&...) const {} - static std::string GetName(int id) { return ""; } + static std::string GetName(int /* id */) { return ""; } std::string GetName() const { return ""; } - void SetName(std::string name) const {} + void SetName(std::string /* name */) const {} #endif // NETGEN_TRACE_MEMORY }; } // namespace ngcore diff --git a/libsrc/core/table.hpp b/libsrc/core/table.hpp index 7471b6a3..34f40c93 100644 --- a/libsrc/core/table.hpp +++ b/libsrc/core/table.hpp @@ -192,7 +192,7 @@ namespace ngcore using FlatTable::operator[]; - NETGEN_INLINE void StartMemoryTracing (int mem_id) + NETGEN_INLINE void StartMemoryTracing (int /* mem_id */) { mt.Alloc(GetMemUsage()); } diff --git a/libsrc/core/taskmanager.hpp b/libsrc/core/taskmanager.hpp index d9239be9..7025ce3d 100644 --- a/libsrc/core/taskmanager.hpp +++ b/libsrc/core/taskmanager.hpp @@ -1068,11 +1068,11 @@ public: { static Timer timer("ComputeColoring - "+Demangle(typeid(Tmask).name())); RegionTimer rt(timer); static_assert(sizeof(unsigned int)==4, "Adapt type of mask array"); - auto n = colors.Size(); + size_t n = colors.Size(); Array mask(ndofs); - int colored_blocks = 0; + size_t colored_blocks = 0; // We are coloring with 32 colors at once and use each bit to mask conflicts unsigned int check = 0; diff --git a/libsrc/core/xbool.hpp b/libsrc/core/xbool.hpp index 2063ebf7..fd0da95e 100644 --- a/libsrc/core/xbool.hpp +++ b/libsrc/core/xbool.hpp @@ -20,12 +20,12 @@ namespace ngcore public: xbool (bool b) : state(b ? 2 : 0) { ; } - xbool (TMAYBE x) : state(1) { ; } + xbool (TMAYBE /* x */) : state(1) { ; } xbool () = default; xbool (const xbool &) = default; xbool & operator= (bool b) { state = b ? 2 : 0; return *this; } - xbool & operator= (TMAYBE x) { state = 1; return *this; } + xbool & operator= (TMAYBE /* x */) { state = 1; return *this; } bool IsTrue () const { return state == 2; } bool IsMaybe () const { return state == 1; } From b2fea6dec1bca536570b3b7d290866ae6eb0d8f8 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Thu, 18 Feb 2021 11:37:05 +0100 Subject: [PATCH 337/384] Clean up multiple definitions of DLL_HEADER - define DLL_HEADER only once in mydefs.hpp - define/use NGLIB_API in nglib.h - use NGCORE_API_EXPORT for explicit export of symbols --- libsrc/geom2d/CMakeLists.txt | 2 +- libsrc/geom2d/python_geom2d.cpp | 2 +- libsrc/include/mydefs.hpp | 15 +--- libsrc/include/nginterface.h | 11 +-- libsrc/include/nginterface_v2.hpp | 2 +- libsrc/stlgeom/CMakeLists.txt | 1 + libsrc/stlgeom/python_stl.cpp | 6 +- libsrc/stlgeom/vsstl.cpp | 7 +- libsrc/stlgeom/vsstl.hpp | 18 ++-- ng/gui.cpp | 16 +--- ng/netgenpy.cpp | 26 +++--- nglib/nglib.cpp | 130 ++++++++++++++--------------- nglib/nglib.h | 134 +++++++++++++++--------------- nglib/parallelfunc.cpp | 2 +- 14 files changed, 168 insertions(+), 204 deletions(-) diff --git a/libsrc/geom2d/CMakeLists.txt b/libsrc/geom2d/CMakeLists.txt index eafec27c..26fe62fc 100644 --- a/libsrc/geom2d/CMakeLists.txt +++ b/libsrc/geom2d/CMakeLists.txt @@ -1,4 +1,4 @@ -add_definitions(-DNGLIB_EXPORTS) +add_definitions(-DNGINTERFACE_EXPORTS) add_library(geom2d ${NG_LIB_TYPE} csg2d.cpp genmesh2d.cpp geometry2d.cpp python_geom2d.cpp ) if(APPLE) set_target_properties( geom2d PROPERTIES SUFFIX ".so") diff --git a/libsrc/geom2d/python_geom2d.cpp b/libsrc/geom2d/python_geom2d.cpp index 7fc88d19..2b01e566 100644 --- a/libsrc/geom2d/python_geom2d.cpp +++ b/libsrc/geom2d/python_geom2d.cpp @@ -17,7 +17,7 @@ namespace netgen } -DLL_HEADER void ExportGeom2d(py::module &m) +NGCORE_API_EXPORT void ExportGeom2d(py::module &m) { py::class_> (m, "Spline", "Spline of a SplineGeometry object") diff --git a/libsrc/include/mydefs.hpp b/libsrc/include/mydefs.hpp index f2368ce7..41369e6a 100644 --- a/libsrc/include/mydefs.hpp +++ b/libsrc/include/mydefs.hpp @@ -11,22 +11,15 @@ defines for graphics, testmodes, ... */ +#include #define PACKAGE_VERSION "6.2-dev" // #define DEBUG -#ifdef WIN32 - #if NGINTERFACE_EXPORTS || NGLIB_EXPORTS || nglib_EXPORTS - #define DLL_HEADER __declspec(dllexport) - #else - #define DLL_HEADER __declspec(dllimport) - #endif +#if defined(NGINTERFACE_EXPORTS) || ( defined(WIN32) && (defined(NGLIB_EXPORTS) || defined(nglib_EXPORTS)) ) + #define DLL_HEADER NGCORE_API_EXPORT #else - #if __GNUC__ >= 4 - #define DLL_HEADER __attribute__ ((visibility ("default"))) - #else - #define DLL_HEADER - #endif + #define DLL_HEADER NGCORE_API_IMPORT #endif diff --git a/libsrc/include/nginterface.h b/libsrc/include/nginterface.h index c09f18f0..cea9558b 100644 --- a/libsrc/include/nginterface.h +++ b/libsrc/include/nginterface.h @@ -11,22 +11,13 @@ /* Date: 20. Nov. 99 */ /**************************************************************************/ -#include +#include "mydefs.hpp" /* Application program interface to Netgen */ -#ifndef DLL_HEADER - #if NGINTERFACE_EXPORTS || NGLIB_EXPORTS || nglib_EXPORTS - #define DLL_HEADER NGCORE_API_EXPORT - #else - #define DLL_HEADER NGCORE_API_IMPORT - #endif -#endif - - // max number of nodes per element #define NG_ELEMENT_MAXPOINTS 20 diff --git a/libsrc/include/nginterface_v2.hpp b/libsrc/include/nginterface_v2.hpp index de18cf05..f2f9734b 100644 --- a/libsrc/include/nginterface_v2.hpp +++ b/libsrc/include/nginterface_v2.hpp @@ -8,7 +8,7 @@ /* Date: May 09 */ /**************************************************************************/ -#include +#include "mydefs.hpp" /* C++ interface to Netgen diff --git a/libsrc/stlgeom/CMakeLists.txt b/libsrc/stlgeom/CMakeLists.txt index 81d4e836..8efefbca 100644 --- a/libsrc/stlgeom/CMakeLists.txt +++ b/libsrc/stlgeom/CMakeLists.txt @@ -1,3 +1,4 @@ +add_definitions(-DNGINTERFACE_EXPORTS) add_library(stl ${NG_LIB_TYPE} meshstlsurface.cpp stlgeom.cpp stlgeomchart.cpp stlgeommesh.cpp stlline.cpp stltool.cpp stltopology.cpp python_stl.cpp diff --git a/libsrc/stlgeom/python_stl.cpp b/libsrc/stlgeom/python_stl.cpp index accfb8d6..74b2c3f4 100644 --- a/libsrc/stlgeom/python_stl.cpp +++ b/libsrc/stlgeom/python_stl.cpp @@ -6,10 +6,6 @@ #include #include "../meshing/python_mesh.hpp" -#ifdef WIN32 - #define DLL_HEADER __declspec(dllexport) -#endif - using namespace netgen; namespace netgen { @@ -125,7 +121,7 @@ void CreateSTLParametersFromKwargs(STLParameters& stlparam, py::dict kwargs) } -DLL_HEADER void ExportSTL(py::module & m) +NGCORE_API_EXPORT void ExportSTL(py::module & m) { py::class_, NetgenGeometry> (m,"STLGeometry") .def(py::init<>()) diff --git a/libsrc/stlgeom/vsstl.cpp b/libsrc/stlgeom/vsstl.cpp index b8ef117f..63202fdb 100644 --- a/libsrc/stlgeom/vsstl.cpp +++ b/libsrc/stlgeom/vsstl.cpp @@ -1216,13 +1216,10 @@ void VisualSceneSTLMeshing :: MouseDblClick (int px, int py) #ifdef NG_PYTHON -#ifdef WIN32 - #define DLL_HEADER __declspec(dllexport) -#endif - #include <../general/ngpython.hpp> +#include -DLL_HEADER void ExportSTLVis(py::module &m) +NGCORE_API_EXPORT void ExportSTLVis(py::module &m) { using namespace netgen; diff --git a/libsrc/stlgeom/vsstl.hpp b/libsrc/stlgeom/vsstl.hpp index ea1a5b72..f36dcac2 100644 --- a/libsrc/stlgeom/vsstl.hpp +++ b/libsrc/stlgeom/vsstl.hpp @@ -10,30 +10,30 @@ namespace netgen { - class VisualSceneSTLGeometry : public VisualScene + class DLL_HEADER VisualSceneSTLGeometry : public VisualScene { NgArray trilists; class STLGeometry * stlgeometry; public: - DLL_HEADER VisualSceneSTLGeometry (); - DLL_HEADER virtual ~VisualSceneSTLGeometry (); - void SetGeometry (class STLGeometry * astlgeometry) { stlgeometry = astlgeometry; } + VisualSceneSTLGeometry (); + virtual ~VisualSceneSTLGeometry (); + void SetGeometry (class STLGeometry * astlgeometry) { stlgeometry = astlgeometry; } - DLL_HEADER virtual void BuildScene (int zoomall = 0); - DLL_HEADER virtual void DrawScene (); + virtual void BuildScene (int zoomall = 0); + virtual void DrawScene (); }; - class VisualSceneSTLMeshing : public VisualScene + class DLL_HEADER VisualSceneSTLMeshing : public VisualScene { NgArray trilists; int selecttrig, nodeofseltrig; class STLGeometry * stlgeometry; public: - DLL_HEADER VisualSceneSTLMeshing (); - DLL_HEADER virtual ~VisualSceneSTLMeshing (); + VisualSceneSTLMeshing (); + virtual ~VisualSceneSTLMeshing (); void SetGeometry (class STLGeometry * astlgeometry) { stlgeometry = astlgeometry; } diff --git a/ng/gui.cpp b/ng/gui.cpp index 680a3417..49e970bc 100644 --- a/ng/gui.cpp +++ b/ng/gui.cpp @@ -1,29 +1,21 @@ #include #include #include - -#ifdef WIN32 - #define DLL_HEADER_IMPORT __declspec(dllimport) - #define DLL_HEADER_EXPORT __declspec(dllexport) -#else - #define DLL_HEADER_IMPORT - #define DLL_HEADER_EXPORT -#endif - +#include namespace netgen { - DLL_HEADER_EXPORT Flags parameters; + NGCORE_API_EXPORT Flags parameters; } -DLL_HEADER_EXPORT bool nodisplay = false; +NGCORE_API_EXPORT bool nodisplay = false; extern "C" int Ng_Init (Tcl_Interp * interp); extern "C" int Ng_Vis_Init (Tcl_Interp * interp); extern "C" void Ng_TclCmd(string); // tcl package dynamic load -extern "C" int DLL_HEADER_EXPORT Gui_Init (Tcl_Interp * interp) +extern "C" int NGCORE_API_EXPORT Gui_Init (Tcl_Interp * interp) { if (Ng_Init(interp) == TCL_ERROR) { cerr << "Problem in Ng_Init: " << endl; diff --git a/ng/netgenpy.cpp b/ng/netgenpy.cpp index 2b68e408..08aca5db 100644 --- a/ng/netgenpy.cpp +++ b/ng/netgenpy.cpp @@ -2,27 +2,21 @@ #include #include <../general/ngpython.hpp> +#include -#ifdef WIN32 -#define DLL_HEADER __declspec(dllimport) -#else -#define DLL_HEADER -#endif - - -void DLL_HEADER ExportNetgenMeshing(py::module &m); -void DLL_HEADER ExportMeshVis(py::module &m); -void DLL_HEADER ExportCSG(py::module &m); -void DLL_HEADER ExportCSGVis(py::module &m); -void DLL_HEADER ExportGeom2d(py::module &m); -void DLL_HEADER ExportSTL(py::module &m); -void DLL_HEADER ExportSTLVis(py::module &m); +void NGCORE_API_IMPORT ExportNetgenMeshing(py::module &m); +void NGCORE_API_IMPORT ExportMeshVis(py::module &m); +void NGCORE_API_IMPORT ExportCSG(py::module &m); +void NGCORE_API_IMPORT ExportCSGVis(py::module &m); +void NGCORE_API_IMPORT ExportGeom2d(py::module &m); +void NGCORE_API_IMPORT ExportSTL(py::module &m); +void NGCORE_API_IMPORT ExportSTLVis(py::module &m); #ifdef OCCGEOMETRY -void DLL_HEADER ExportNgOCC(py::module &m); +void NGCORE_API_IMPORT ExportNgOCC(py::module &m); #endif // OCCGEOMETRY namespace netgen { - std::vector DLL_HEADER Snapshot( int w, int h ); + std::vector NGCORE_API_IMPORT Snapshot( int w, int h ); } PYBIND11_MODULE(libngpy, ngpy) diff --git a/nglib/nglib.cpp b/nglib/nglib.cpp index 7e039249..9eb1e8c3 100644 --- a/nglib/nglib.cpp +++ b/nglib/nglib.cpp @@ -78,7 +78,7 @@ namespace nglib // initialize, deconstruct Netgen library: - DLL_HEADER void Ng_Init () + NGLIB_API void Ng_Init () { mycout = &cout; myerr = &cerr; @@ -90,7 +90,7 @@ namespace nglib // Clean-up functions before ending usage of nglib - DLL_HEADER void Ng_Exit () + NGLIB_API void Ng_Exit () { ; } @@ -99,7 +99,7 @@ namespace nglib // Create a new netgen mesh object - DLL_HEADER Ng_Mesh * Ng_NewMesh () + NGLIB_API Ng_Mesh * Ng_NewMesh () { Mesh * mesh = new Mesh; mesh->AddFaceDescriptor (FaceDescriptor (1, 1, 0, 1)); @@ -110,7 +110,7 @@ namespace nglib // Delete an existing netgen mesh object - DLL_HEADER void Ng_DeleteMesh (Ng_Mesh * mesh) + NGLIB_API void Ng_DeleteMesh (Ng_Mesh * mesh) { if(mesh != NULL) { @@ -129,7 +129,7 @@ namespace nglib // Save a netgen mesh in the native VOL format - DLL_HEADER void Ng_SaveMesh(Ng_Mesh * mesh, const char* filename) + NGLIB_API void Ng_SaveMesh(Ng_Mesh * mesh, const char* filename) { ((Mesh*)mesh)->Save(filename); } @@ -138,7 +138,7 @@ namespace nglib // Load a netgen native VOL mesh from a given file - DLL_HEADER Ng_Mesh * Ng_LoadMesh(const char* filename) + NGLIB_API Ng_Mesh * Ng_LoadMesh(const char* filename) { Mesh * mesh = new Mesh; mesh->Load(filename); @@ -149,7 +149,7 @@ namespace nglib // Merge another mesh file into the currently loaded one - DLL_HEADER Ng_Result Ng_MergeMesh( Ng_Mesh* mesh, const char* filename) + NGLIB_API Ng_Result Ng_MergeMesh( Ng_Mesh* mesh, const char* filename) { Ng_Result status = NG_OK; @@ -190,7 +190,7 @@ namespace nglib // Merge another mesh file into the currently loaded one - DLL_HEADER Ng_Result Ng_MergeMesh( Ng_Mesh* mesh1, Ng_Mesh* mesh2) + NGLIB_API Ng_Result Ng_MergeMesh( Ng_Mesh* mesh1, Ng_Mesh* mesh2) { return NG_ERROR; } @@ -199,7 +199,7 @@ namespace nglib // Manually add a point to an existing mesh object - DLL_HEADER void Ng_AddPoint (Ng_Mesh * mesh, double * x) + NGLIB_API void Ng_AddPoint (Ng_Mesh * mesh, double * x) { Mesh * m = (Mesh*)mesh; m->AddPoint (Point3d (x[0], x[1], x[2])); @@ -209,7 +209,7 @@ namespace nglib // Manually add a surface element of a given type to an existing mesh object - DLL_HEADER void Ng_AddSurfaceElement (Ng_Mesh * mesh, Ng_Surface_Element_Type et, + NGLIB_API void Ng_AddSurfaceElement (Ng_Mesh * mesh, Ng_Surface_Element_Type et, int * pi) { Mesh * m = (Mesh*)mesh; @@ -225,7 +225,7 @@ namespace nglib // Manually add a volume element of a given type to an existing mesh object - DLL_HEADER void Ng_AddVolumeElement (Ng_Mesh * mesh, Ng_Volume_Element_Type et, + NGLIB_API void Ng_AddVolumeElement (Ng_Mesh * mesh, Ng_Volume_Element_Type et, int * pi) { Mesh * m = (Mesh*)mesh; @@ -242,7 +242,7 @@ namespace nglib // Obtain the number of points in the mesh - DLL_HEADER int Ng_GetNP (Ng_Mesh * mesh) + NGLIB_API int Ng_GetNP (Ng_Mesh * mesh) { return ((Mesh*)mesh) -> GetNP(); } @@ -251,7 +251,7 @@ namespace nglib // Obtain the number of surface elements in the mesh - DLL_HEADER int Ng_GetNSE (Ng_Mesh * mesh) + NGLIB_API int Ng_GetNSE (Ng_Mesh * mesh) { return ((Mesh*)mesh) -> GetNSE(); } @@ -260,7 +260,7 @@ namespace nglib // Obtain the number of volume elements in the mesh - DLL_HEADER int Ng_GetNE (Ng_Mesh * mesh) + NGLIB_API int Ng_GetNE (Ng_Mesh * mesh) { return ((Mesh*)mesh) -> GetNE(); } @@ -269,7 +269,7 @@ namespace nglib // Return point coordinates of a given point index in the mesh - DLL_HEADER void Ng_GetPoint (Ng_Mesh * mesh, int num, double * x) + NGLIB_API void Ng_GetPoint (Ng_Mesh * mesh, int num, double * x) { const Point3d & p = ((Mesh*)mesh)->Point(num); x[0] = p.X(); @@ -281,7 +281,7 @@ namespace nglib // Return the surface element at a given index "pi" - DLL_HEADER Ng_Surface_Element_Type + NGLIB_API Ng_Surface_Element_Type Ng_GetSurfaceElement (Ng_Mesh * mesh, int num, int * pi) { const Element2d & el = ((Mesh*)mesh)->SurfaceElement(num); @@ -312,7 +312,7 @@ namespace nglib // Return the volume element at a given index "pi" - DLL_HEADER Ng_Volume_Element_Type + NGLIB_API Ng_Volume_Element_Type Ng_GetVolumeElement (Ng_Mesh * mesh, int num, int * pi) { const Element & el = ((Mesh*)mesh)->VolumeElement(num); @@ -335,7 +335,7 @@ namespace nglib // Set a global limit on the maximum mesh size allowed - DLL_HEADER void Ng_RestrictMeshSizeGlobal (Ng_Mesh * mesh, double h) + NGLIB_API void Ng_RestrictMeshSizeGlobal (Ng_Mesh * mesh, double h) { ((Mesh*)mesh) -> SetGlobalH (h); } @@ -344,7 +344,7 @@ namespace nglib // Set a local limit on the maximum mesh size allowed around the given point - DLL_HEADER void Ng_RestrictMeshSizePoint (Ng_Mesh * mesh, double * p, double h) + NGLIB_API void Ng_RestrictMeshSizePoint (Ng_Mesh * mesh, double * p, double h) { ((Mesh*)mesh) -> RestrictLocalH (Point3d (p[0], p[1], p[2]), h); } @@ -353,7 +353,7 @@ namespace nglib // Set a local limit on the maximum mesh size allowed within a given box region - DLL_HEADER void Ng_RestrictMeshSizeBox (Ng_Mesh * mesh, double * pmin, double * pmax, double h) + NGLIB_API void Ng_RestrictMeshSizeBox (Ng_Mesh * mesh, double * pmin, double * pmax, double h) { for (double x = pmin[0]; x < pmax[0]; x += h) for (double y = pmin[1]; y < pmax[1]; y += h) @@ -365,7 +365,7 @@ namespace nglib // Generates volume mesh from an existing surface mesh - DLL_HEADER Ng_Result Ng_GenerateVolumeMesh (Ng_Mesh * mesh, Ng_Meshing_Parameters * mp) + NGLIB_API Ng_Result Ng_GenerateVolumeMesh (Ng_Mesh * mesh, Ng_Meshing_Parameters * mp) { Mesh * m = (Mesh*)mesh; @@ -388,7 +388,7 @@ namespace nglib /* ------------------ 2D Meshing Functions ------------------------- */ - DLL_HEADER void Ng_AddPoint_2D (Ng_Mesh * mesh, double * x) + NGLIB_API void Ng_AddPoint_2D (Ng_Mesh * mesh, double * x) { Mesh * m = (Mesh*)mesh; @@ -398,7 +398,7 @@ namespace nglib - DLL_HEADER void Ng_AddBoundarySeg_2D (Ng_Mesh * mesh, int pi1, int pi2) + NGLIB_API void Ng_AddBoundarySeg_2D (Ng_Mesh * mesh, int pi1, int pi2) { Mesh * m = (Mesh*)mesh; @@ -411,7 +411,7 @@ namespace nglib - DLL_HEADER int Ng_GetNP_2D (Ng_Mesh * mesh) + NGLIB_API int Ng_GetNP_2D (Ng_Mesh * mesh) { Mesh * m = (Mesh*)mesh; return m->GetNP(); @@ -420,7 +420,7 @@ namespace nglib - DLL_HEADER int Ng_GetNE_2D (Ng_Mesh * mesh) + NGLIB_API int Ng_GetNE_2D (Ng_Mesh * mesh) { Mesh * m = (Mesh*)mesh; return m->GetNSE(); @@ -429,7 +429,7 @@ namespace nglib - DLL_HEADER int Ng_GetNSeg_2D (Ng_Mesh * mesh) + NGLIB_API int Ng_GetNSeg_2D (Ng_Mesh * mesh) { Mesh * m = (Mesh*)mesh; return m->GetNSeg(); @@ -438,7 +438,7 @@ namespace nglib - DLL_HEADER void Ng_GetPoint_2D (Ng_Mesh * mesh, int num, double * x) + NGLIB_API void Ng_GetPoint_2D (Ng_Mesh * mesh, int num, double * x) { Mesh * m = (Mesh*)mesh; @@ -450,7 +450,7 @@ namespace nglib - DLL_HEADER Ng_Surface_Element_Type + NGLIB_API Ng_Surface_Element_Type Ng_GetElement_2D (Ng_Mesh * mesh, int num, int * pi, int * matnum) { const Element2d & el = ((Mesh*)mesh)->SurfaceElement(num); @@ -485,7 +485,7 @@ namespace nglib - DLL_HEADER void Ng_GetSegment_2D (Ng_Mesh * mesh, int num, int * pi, int * matnum) + NGLIB_API void Ng_GetSegment_2D (Ng_Mesh * mesh, int num, int * pi, int * matnum) { const Segment & seg = ((Mesh*)mesh)->LineSegment(num); pi[0] = seg[0]; @@ -498,7 +498,7 @@ namespace nglib - DLL_HEADER Ng_Geometry_2D * Ng_LoadGeometry_2D (const char * filename) + NGLIB_API Ng_Geometry_2D * Ng_LoadGeometry_2D (const char * filename) { SplineGeometry2d * geom = new SplineGeometry2d(); geom -> Load (filename); @@ -506,7 +506,7 @@ namespace nglib } - DLL_HEADER Ng_Result Ng_GenerateMesh_2D (Ng_Geometry_2D * geom, + NGLIB_API Ng_Result Ng_GenerateMesh_2D (Ng_Geometry_2D * geom, Ng_Mesh ** mesh, Ng_Meshing_Parameters * mp) { @@ -527,7 +527,7 @@ namespace nglib - DLL_HEADER void Ng_HP_Refinement (Ng_Geometry_2D * geom, + NGLIB_API void Ng_HP_Refinement (Ng_Geometry_2D * geom, Ng_Mesh * mesh, int levels) { @@ -538,7 +538,7 @@ namespace nglib - DLL_HEADER void Ng_HP_Refinement (Ng_Geometry_2D * geom, + NGLIB_API void Ng_HP_Refinement (Ng_Geometry_2D * geom, Ng_Mesh * mesh, int levels, double parameter) { @@ -553,7 +553,7 @@ namespace nglib NgArray > readedges; //only before init stlgeometry // loads geometry from STL file - DLL_HEADER Ng_STL_Geometry * Ng_STL_LoadGeometry (const char * filename, int binary) + NGLIB_API Ng_STL_Geometry * Ng_STL_LoadGeometry (const char * filename, int binary) { int i; STLGeometry geom; @@ -603,7 +603,7 @@ namespace nglib // generate new STL Geometry - DLL_HEADER Ng_STL_Geometry * Ng_STL_NewGeometry () + NGLIB_API Ng_STL_Geometry * Ng_STL_NewGeometry () { return (Ng_STL_Geometry*)(void*)new STLGeometry; } @@ -612,7 +612,7 @@ namespace nglib // after adding triangles (and edges) initialize - DLL_HEADER Ng_Result Ng_STL_InitSTLGeometry (Ng_STL_Geometry * geom) + NGLIB_API Ng_Result Ng_STL_InitSTLGeometry (Ng_STL_Geometry * geom) { STLGeometry* geo = (STLGeometry*)geom; geo->InitSTLGeometry(readtrias); @@ -637,7 +637,7 @@ namespace nglib // automatically generates edges: - DLL_HEADER Ng_Result Ng_STL_MakeEdges (Ng_STL_Geometry * geom, + NGLIB_API Ng_Result Ng_STL_MakeEdges (Ng_STL_Geometry * geom, Ng_Mesh* mesh, Ng_Meshing_Parameters * mp) { @@ -683,7 +683,7 @@ namespace nglib // generates mesh, empty mesh be already created. - DLL_HEADER Ng_Result Ng_STL_GenerateSurfaceMesh (Ng_STL_Geometry * geom, + NGLIB_API Ng_Result Ng_STL_GenerateSurfaceMesh (Ng_STL_Geometry * geom, Ng_Mesh* mesh, Ng_Meshing_Parameters * mp) { @@ -745,7 +745,7 @@ namespace nglib // fills STL Geometry // positive orientation // normal vector may be null-pointer - DLL_HEADER void Ng_STL_AddTriangle (Ng_STL_Geometry * geom, + NGLIB_API void Ng_STL_AddTriangle (Ng_STL_Geometry * geom, double * p1, double * p2, double * p3, double * nv) { @@ -764,7 +764,7 @@ namespace nglib } // add (optional) edges: - DLL_HEADER void Ng_STL_AddEdge (Ng_STL_Geometry * geom, + NGLIB_API void Ng_STL_AddEdge (Ng_STL_Geometry * geom, double * p1, double * p2) { readedges.Append(Point3d(p1[0],p1[1],p1[2])); @@ -777,7 +777,7 @@ namespace nglib #ifdef OCCGEOMETRY // --------------------- OCC Geometry / Meshing Utility Functions ------------------- // Create new OCC Geometry Object - DLL_HEADER Ng_OCC_Geometry * Ng_OCC_NewGeometry () + NGLIB_API Ng_OCC_Geometry * Ng_OCC_NewGeometry () { return (Ng_OCC_Geometry*)(void*)new OCCGeometry; } @@ -786,7 +786,7 @@ namespace nglib // Delete the OCC Geometry Object - DLL_HEADER Ng_Result Ng_OCC_DeleteGeometry(Ng_OCC_Geometry * geom) + NGLIB_API Ng_Result Ng_OCC_DeleteGeometry(Ng_OCC_Geometry * geom) { if (geom != NULL) { @@ -802,7 +802,7 @@ namespace nglib // Loads geometry from STEP File - DLL_HEADER Ng_OCC_Geometry * Ng_OCC_Load_STEP (const char * filename) + NGLIB_API Ng_OCC_Geometry * Ng_OCC_Load_STEP (const char * filename) { // Call the STEP File Load function. Note.. the geometry class // is created and instantiated within the load function @@ -815,7 +815,7 @@ namespace nglib // Loads geometry from IGES File - DLL_HEADER Ng_OCC_Geometry * Ng_OCC_Load_IGES (const char * filename) + NGLIB_API Ng_OCC_Geometry * Ng_OCC_Load_IGES (const char * filename) { // Call the IGES File Load function. Note.. the geometry class // is created and instantiated within the load function @@ -828,7 +828,7 @@ namespace nglib // Loads geometry from BREP File - DLL_HEADER Ng_OCC_Geometry * Ng_OCC_Load_BREP (const char * filename) + NGLIB_API Ng_OCC_Geometry * Ng_OCC_Load_BREP (const char * filename) { // Call the BREP File Load function. Note.. the geometry class // is created and instantiated within the load function @@ -842,7 +842,7 @@ namespace nglib // Locally limit the size of the mesh to be generated at various points // based on the topology of the geometry - DLL_HEADER Ng_Result Ng_OCC_SetLocalMeshSize (Ng_OCC_Geometry * geom, + NGLIB_API Ng_Result Ng_OCC_SetLocalMeshSize (Ng_OCC_Geometry * geom, Ng_Mesh * mesh, Ng_Meshing_Parameters * mp) { @@ -870,7 +870,7 @@ namespace nglib // Mesh the edges and add Face descriptors to prepare for surface meshing - DLL_HEADER Ng_Result Ng_OCC_GenerateEdgeMesh (Ng_OCC_Geometry * geom, + NGLIB_API Ng_Result Ng_OCC_GenerateEdgeMesh (Ng_OCC_Geometry * geom, Ng_Mesh * mesh, Ng_Meshing_Parameters * mp) { @@ -896,7 +896,7 @@ namespace nglib // Mesh the edges and add Face descriptors to prepare for surface meshing - DLL_HEADER Ng_Result Ng_OCC_GenerateSurfaceMesh (Ng_OCC_Geometry * geom, + NGLIB_API Ng_Result Ng_OCC_GenerateSurfaceMesh (Ng_OCC_Geometry * geom, Ng_Mesh * mesh, Ng_Meshing_Parameters * mp) { @@ -946,7 +946,7 @@ namespace nglib // Extract the face map from the OCC geometry // The face map basically gives an index to each face in the geometry, // which can be used to access a specific face - DLL_HEADER Ng_Result Ng_OCC_GetFMap(Ng_OCC_Geometry * geom, + NGLIB_API Ng_Result Ng_OCC_GetFMap(Ng_OCC_Geometry * geom, Ng_OCC_TopTools_IndexedMapOfShape * FMap) { OCCGeometry* occgeom = (OCCGeometry*)geom; @@ -973,7 +973,7 @@ namespace nglib // ------------------ Begin - Meshing Parameters related functions ------------------ // Constructor for the local nglib meshing parameters class - DLL_HEADER Ng_Meshing_Parameters :: Ng_Meshing_Parameters() + NGLIB_API Ng_Meshing_Parameters :: Ng_Meshing_Parameters() { uselocalh = 1; @@ -1014,7 +1014,7 @@ namespace nglib // Reset the local meshing parameters to the default values - DLL_HEADER void Ng_Meshing_Parameters :: Reset_Parameters() + NGLIB_API void Ng_Meshing_Parameters :: Reset_Parameters() { uselocalh = 1; @@ -1055,7 +1055,7 @@ namespace nglib // - DLL_HEADER void Ng_Meshing_Parameters :: Transfer_Parameters() + NGLIB_API void Ng_Meshing_Parameters :: Transfer_Parameters() { mparam.uselocalh = uselocalh; @@ -1088,7 +1088,7 @@ namespace nglib // ------------------ Begin - Second Order Mesh generation functions ---------------- - DLL_HEADER void Ng_Generate_SecondOrder(Ng_Mesh * mesh) + NGLIB_API void Ng_Generate_SecondOrder(Ng_Mesh * mesh) { Refinement ref(*((Mesh*) mesh)->GetGeometry()); ref.MakeSecondOrder(*(Mesh*) mesh); @@ -1097,7 +1097,7 @@ namespace nglib - DLL_HEADER void Ng_2D_Generate_SecondOrder(Ng_Geometry_2D * geom, + NGLIB_API void Ng_2D_Generate_SecondOrder(Ng_Geometry_2D * geom, Ng_Mesh * mesh) { ( (SplineGeometry2d*)geom ) -> GetRefinement().MakeSecondOrder( * (Mesh*) mesh ); @@ -1106,7 +1106,7 @@ namespace nglib - DLL_HEADER void Ng_STL_Generate_SecondOrder(Ng_STL_Geometry * geom, + NGLIB_API void Ng_STL_Generate_SecondOrder(Ng_STL_Geometry * geom, Ng_Mesh * mesh) { ((STLGeometry*)geom)->GetRefinement().MakeSecondOrder(*(Mesh*) mesh); @@ -1115,7 +1115,7 @@ namespace nglib - DLL_HEADER void Ng_CSG_Generate_SecondOrder (Ng_CSG_Geometry * geom, + NGLIB_API void Ng_CSG_Generate_SecondOrder (Ng_CSG_Geometry * geom, Ng_Mesh * mesh) { ((CSGeometry*)geom)->GetRefinement().MakeSecondOrder(*(Mesh*) mesh); @@ -1125,7 +1125,7 @@ namespace nglib #ifdef OCCGEOMETRY - DLL_HEADER void Ng_OCC_Generate_SecondOrder (Ng_OCC_Geometry * geom, + NGLIB_API void Ng_OCC_Generate_SecondOrder (Ng_OCC_Geometry * geom, Ng_Mesh * mesh) { ((OCCGeometry*)geom )->GetRefinement().MakeSecondOrder(*(Mesh*) mesh); @@ -1137,7 +1137,7 @@ namespace nglib // ------------------ Begin - Uniform Mesh Refinement functions --------------------- - DLL_HEADER void Ng_Uniform_Refinement (Ng_Mesh * mesh) + NGLIB_API void Ng_Uniform_Refinement (Ng_Mesh * mesh) { Refinement ref(*((Mesh*)mesh)->GetGeometry()); ref.Refine ( * (Mesh*) mesh ); @@ -1146,7 +1146,7 @@ namespace nglib - DLL_HEADER void Ng_2D_Uniform_Refinement (Ng_Geometry_2D * geom, + NGLIB_API void Ng_2D_Uniform_Refinement (Ng_Geometry_2D * geom, Ng_Mesh * mesh) { ( (SplineGeometry2d*)geom ) -> GetRefinement().Refine ( * (Mesh*) mesh ); @@ -1155,7 +1155,7 @@ namespace nglib - DLL_HEADER void Ng_STL_Uniform_Refinement (Ng_STL_Geometry * geom, + NGLIB_API void Ng_STL_Uniform_Refinement (Ng_STL_Geometry * geom, Ng_Mesh * mesh) { ( (STLGeometry*)geom ) -> GetRefinement().Refine ( * (Mesh*) mesh ); @@ -1164,7 +1164,7 @@ namespace nglib - DLL_HEADER void Ng_CSG_Uniform_Refinement (Ng_CSG_Geometry * geom, + NGLIB_API void Ng_CSG_Uniform_Refinement (Ng_CSG_Geometry * geom, Ng_Mesh * mesh) { ( (CSGeometry*)geom ) -> GetRefinement().Refine ( * (Mesh*) mesh ); @@ -1174,7 +1174,7 @@ namespace nglib #ifdef OCCGEOMETRY - DLL_HEADER void Ng_OCC_Uniform_Refinement (Ng_OCC_Geometry * geom, + NGLIB_API void Ng_OCC_Uniform_Refinement (Ng_OCC_Geometry * geom, Ng_Mesh * mesh) { ( (OCCGeometry*)geom ) -> GetRefinement().Refine ( * (Mesh*) mesh ); @@ -1191,7 +1191,7 @@ namespace netgen { char geomfilename[255]; - DLL_HEADER void MyError2 (const char * ch) + NGLIB_API void MyError2 (const char * ch) { cerr << ch; } @@ -1200,7 +1200,7 @@ namespace netgen //Destination for messages, errors, ... - DLL_HEADER void Ng_PrintDest2(const char * s) + NGLIB_API void Ng_PrintDest2(const char * s) { #ifdef PARALLEL int id = 0; @@ -1212,7 +1212,7 @@ namespace netgen /* - DLL_HEADER double GetTime () + NGLIB_API double GetTime () { return 0; } diff --git a/nglib/nglib.h b/nglib/nglib.h index 286db0cb..511c62bf 100644 --- a/nglib/nglib.h +++ b/nglib/nglib.h @@ -23,15 +23,15 @@ // Philippose - 14.02.2009 // Modifications for creating a DLL in Windows -#ifndef DLL_HEADER +#ifndef NGLIB_API #ifdef WIN32 #ifdef NGLIB_EXPORTS || nglib_EXPORTS - #define DLL_HEADER __declspec(dllexport) + #define NGLIB_API __declspec(dllexport) #else - #define DLL_HEADER __declspec(dllimport) + #define NGLIB_API __declspec(dllimport) #endif #else - #define DLL_HEADER __attribute__((visibility("default"))) + #define NGLIB_API __attribute__((visibility("default"))) #endif #endif @@ -156,7 +156,7 @@ public: - #check_overlap: 1 - #check_overlapping_boundary: 1 */ - DLL_HEADER Ng_Meshing_Parameters(); + NGLIB_API Ng_Meshing_Parameters(); @@ -166,7 +166,7 @@ public: This member function resets all the meshing parameters of the object to the default values */ - DLL_HEADER void Reset_Parameters(); + NGLIB_API void Reset_Parameters(); @@ -177,7 +177,7 @@ public: defined in the local meshing parameters structure of nglib into the internal meshing parameters structure used by the Netgen core */ - DLL_HEADER void Transfer_Parameters(); + NGLIB_API void Transfer_Parameters(); }; @@ -194,7 +194,7 @@ public: program before beginning to use the other Netgen specific functions. */ -DLL_HEADER void Ng_Init (); +NGLIB_API void Ng_Init (); /*! \brief Exit the Netgen meshing kernel in a clean manner @@ -202,7 +202,7 @@ DLL_HEADER void Ng_Init (); Use this function to exit the meshing sub-system in a clean and orderly manner. */ -DLL_HEADER void Ng_Exit (); +NGLIB_API void Ng_Exit (); /*! \brief Create a new (and empty) Netgen Mesh Structure @@ -215,7 +215,7 @@ DLL_HEADER void Ng_Exit (); \return Ng_Mesh Pointer to a Netgen Mesh type #Ng_Mesh */ -DLL_HEADER Ng_Mesh * Ng_NewMesh (); +NGLIB_API Ng_Mesh * Ng_NewMesh (); /*! \brief Delete an existing Netgen Mesh Structure @@ -226,7 +226,7 @@ DLL_HEADER Ng_Mesh * Ng_NewMesh (); \param mesh Pointer to an existing Netgen Mesh structure of type #Ng_Mesh */ -DLL_HEADER void Ng_DeleteMesh (Ng_Mesh * mesh); +NGLIB_API void Ng_DeleteMesh (Ng_Mesh * mesh); /*! \brief Save a Netgen Mesh to disk @@ -243,7 +243,7 @@ DLL_HEADER void Ng_DeleteMesh (Ng_Mesh * mesh); name of the file to which the mesh should be saved */ -DLL_HEADER void Ng_SaveMesh(Ng_Mesh * mesh, const char* filename); +NGLIB_API void Ng_SaveMesh(Ng_Mesh * mesh, const char* filename); /*! \brief Load a Netgen VOL Mesh from disk into memory @@ -256,7 +256,7 @@ DLL_HEADER void Ng_SaveMesh(Ng_Mesh * mesh, const char* filename); \return Ng_Mesh Pointer to a Netgen Mesh type #Ng_Mesh containing the mesh loaded from disk */ -DLL_HEADER Ng_Mesh * Ng_LoadMesh(const char* filename); +NGLIB_API Ng_Mesh * Ng_LoadMesh(const char* filename); /*! \brief Merge a Netgen VOL Mesh from disk into an existing mesh in memory @@ -269,7 +269,7 @@ DLL_HEADER Ng_Mesh * Ng_LoadMesh(const char* filename); name of the file to load \return Ng_Result Status of the merge operation */ -DLL_HEADER Ng_Result Ng_MergeMesh(Ng_Mesh * mesh, const char* filename); +NGLIB_API Ng_Result Ng_MergeMesh(Ng_Mesh * mesh, const char* filename); /*! \brief Merge one Netgen Mesh into another Netgen Mesh in the case @@ -286,7 +286,7 @@ DLL_HEADER Ng_Result Ng_MergeMesh(Ng_Mesh * mesh, const char* filename); the parent mesh \return Ng_Result Status of the merge operation */ -DLL_HEADER Ng_Result Ng_MergeMesh(Ng_Mesh * mesh1, Ng_Mesh * mesh2); +NGLIB_API Ng_Result Ng_MergeMesh(Ng_Mesh * mesh1, Ng_Mesh * mesh2); // ------------------------------------------------------------------ @@ -310,7 +310,7 @@ DLL_HEADER Ng_Result Ng_MergeMesh(Ng_Mesh * mesh1, Ng_Mesh * mesh2); - x[1] = Y co-ordinate - x[2] = Z co-ordinate */ -DLL_HEADER void Ng_AddPoint (Ng_Mesh * mesh, double * x); +NGLIB_API void Ng_AddPoint (Ng_Mesh * mesh, double * x); /*! \brief Add a surface element to a given Netgen Mesh Structure @@ -333,7 +333,7 @@ DLL_HEADER void Ng_AddPoint (Ng_Mesh * mesh, double * x); \param pi Pointer to an array of integers containing the indices of the points which constitute the surface element being added */ -DLL_HEADER void Ng_AddSurfaceElement (Ng_Mesh * mesh, Ng_Surface_Element_Type et, int * pi); +NGLIB_API void Ng_AddSurfaceElement (Ng_Mesh * mesh, Ng_Surface_Element_Type et, int * pi); /*! \brief Add a volume element to a given Netgen Mesh Structure @@ -357,7 +357,7 @@ DLL_HEADER void Ng_AddSurfaceElement (Ng_Mesh * mesh, Ng_Surface_Element_Type et points which constitute the volume element being added */ -DLL_HEADER void Ng_AddVolumeElement (Ng_Mesh * mesh, Ng_Volume_Element_Type et, int * pi); +NGLIB_API void Ng_AddVolumeElement (Ng_Mesh * mesh, Ng_Volume_Element_Type et, int * pi); // ------------------------------------------------------------------ @@ -384,7 +384,7 @@ DLL_HEADER void Ng_AddVolumeElement (Ng_Mesh * mesh, Ng_Volume_Element_Type et, \param h Variable of type double, specifying the maximum allowable mesh size */ -DLL_HEADER void Ng_RestrictMeshSizeGlobal (Ng_Mesh * mesh, double h); +NGLIB_API void Ng_RestrictMeshSizeGlobal (Ng_Mesh * mesh, double h); /*! \brief Locally restrict the mesh element size at the given point @@ -408,7 +408,7 @@ DLL_HEADER void Ng_RestrictMeshSizeGlobal (Ng_Mesh * mesh, double h); \param h Variable of type double, specifying the maximum allowable mesh size at that point */ -DLL_HEADER void Ng_RestrictMeshSizePoint (Ng_Mesh * mesh, double * p, double h); +NGLIB_API void Ng_RestrictMeshSizePoint (Ng_Mesh * mesh, double * p, double h); /*! \brief Locally restrict the mesh element size within a specified box @@ -439,7 +439,7 @@ DLL_HEADER void Ng_RestrictMeshSizePoint (Ng_Mesh * mesh, double * p, double h); \param h Variable of type double, specifying the maximum allowable mesh size at that point */ -DLL_HEADER void Ng_RestrictMeshSizeBox (Ng_Mesh * mesh, double * pmin, double * pmax, double h); +NGLIB_API void Ng_RestrictMeshSizeBox (Ng_Mesh * mesh, double * pmin, double * pmax, double h); // ------------------------------------------------------------------ @@ -470,7 +470,7 @@ DLL_HEADER void Ng_RestrictMeshSizeBox (Ng_Mesh * mesh, double * pmin, double * details regarding the return value can be found in the description of #Ng_Result */ -DLL_HEADER Ng_Result Ng_GenerateVolumeMesh (Ng_Mesh * mesh, Ng_Meshing_Parameters * mp); +NGLIB_API Ng_Result Ng_GenerateVolumeMesh (Ng_Mesh * mesh, Ng_Meshing_Parameters * mp); // ------------------------------------------------------------------ @@ -489,7 +489,7 @@ DLL_HEADER Ng_Result Ng_GenerateVolumeMesh (Ng_Mesh * mesh, Ng_Meshing_Parameter \return Integer Data-type with the number of points in the Mesh */ -DLL_HEADER int Ng_GetNP (Ng_Mesh * mesh); +NGLIB_API int Ng_GetNP (Ng_Mesh * mesh); /*! \brief Returns the Number of Surface Elements present in the specified Mesh @@ -503,7 +503,7 @@ DLL_HEADER int Ng_GetNP (Ng_Mesh * mesh); \return Integer Data-type with the number of surface elements in the Mesh */ -DLL_HEADER int Ng_GetNSE (Ng_Mesh * mesh); +NGLIB_API int Ng_GetNSE (Ng_Mesh * mesh); /*! \brief Returns the Number of Volume Elements present in the specified Mesh @@ -517,7 +517,7 @@ DLL_HEADER int Ng_GetNSE (Ng_Mesh * mesh); \return Integer Data-type with the number of volume elements in the Mesh */ -DLL_HEADER int Ng_GetNE (Ng_Mesh * mesh); +NGLIB_API int Ng_GetNE (Ng_Mesh * mesh); // ------------------------------------------------------------------ @@ -531,15 +531,15 @@ DLL_HEADER int Ng_GetNE (Ng_Mesh * mesh); // Return the Point Coordinates of a specified Point // The x, y and z co-ordinates are returned in the array pointer as // x[0] = x ; x[1] = y ; x[2] = z -DLL_HEADER void Ng_GetPoint (Ng_Mesh * mesh, int num, double * x); +NGLIB_API void Ng_GetPoint (Ng_Mesh * mesh, int num, double * x); // return surface and volume element in pi -DLL_HEADER Ng_Surface_Element_Type +NGLIB_API Ng_Surface_Element_Type Ng_GetSurfaceElement (Ng_Mesh * mesh, int num, int * pi); -DLL_HEADER Ng_Volume_Element_Type +NGLIB_API Ng_Volume_Element_Type Ng_GetVolumeElement (Ng_Mesh * mesh, int num, int * pi); // ------------------------------------------------------------------ @@ -554,34 +554,34 @@ Ng_GetVolumeElement (Ng_Mesh * mesh, int num, int * pi); // feeds points and boundary to mesh -DLL_HEADER void Ng_AddPoint_2D (Ng_Mesh * mesh, double * x); -DLL_HEADER void Ng_AddBoundarySeg_2D (Ng_Mesh * mesh, int pi1, int pi2); +NGLIB_API void Ng_AddPoint_2D (Ng_Mesh * mesh, double * x); +NGLIB_API void Ng_AddBoundarySeg_2D (Ng_Mesh * mesh, int pi1, int pi2); // ask for number of points, elements and boundary segments -DLL_HEADER int Ng_GetNP_2D (Ng_Mesh * mesh); -DLL_HEADER int Ng_GetNE_2D (Ng_Mesh * mesh); -DLL_HEADER int Ng_GetNSeg_2D (Ng_Mesh * mesh); +NGLIB_API int Ng_GetNP_2D (Ng_Mesh * mesh); +NGLIB_API int Ng_GetNE_2D (Ng_Mesh * mesh); +NGLIB_API int Ng_GetNSeg_2D (Ng_Mesh * mesh); // return point coordinates -DLL_HEADER void Ng_GetPoint_2D (Ng_Mesh * mesh, int num, double * x); +NGLIB_API void Ng_GetPoint_2D (Ng_Mesh * mesh, int num, double * x); // return 2d elements -DLL_HEADER Ng_Surface_Element_Type +NGLIB_API Ng_Surface_Element_Type Ng_GetElement_2D (Ng_Mesh * mesh, int num, int * pi, int * matnum = NULL); // return 2d boundary segment -DLL_HEADER void Ng_GetSegment_2D (Ng_Mesh * mesh, int num, int * pi, int * matnum = NULL); +NGLIB_API void Ng_GetSegment_2D (Ng_Mesh * mesh, int num, int * pi, int * matnum = NULL); // load 2d netgen spline geometry -DLL_HEADER Ng_Geometry_2D * Ng_LoadGeometry_2D (const char * filename); +NGLIB_API Ng_Geometry_2D * Ng_LoadGeometry_2D (const char * filename); // generate 2d mesh, mesh is allocated by function -DLL_HEADER Ng_Result Ng_GenerateMesh_2D (Ng_Geometry_2D * geom, +NGLIB_API Ng_Result Ng_GenerateMesh_2D (Ng_Geometry_2D * geom, Ng_Mesh ** mesh, Ng_Meshing_Parameters * mp); -DLL_HEADER void Ng_HP_Refinement (Ng_Geometry_2D * geom, +NGLIB_API void Ng_HP_Refinement (Ng_Geometry_2D * geom, Ng_Mesh * mesh, int levels); @@ -595,35 +595,35 @@ DLL_HEADER void Ng_HP_Refinement (Ng_Geometry_2D * geom, // loads geometry from STL file -DLL_HEADER Ng_STL_Geometry * Ng_STL_LoadGeometry (const char * filename, int binary = 0); +NGLIB_API Ng_STL_Geometry * Ng_STL_LoadGeometry (const char * filename, int binary = 0); // generate new STL Geometry -DLL_HEADER Ng_STL_Geometry * Ng_STL_NewGeometry (); +NGLIB_API Ng_STL_Geometry * Ng_STL_NewGeometry (); // fills STL Geometry // positive orientation // normal vector may be null-pointer -DLL_HEADER void Ng_STL_AddTriangle (Ng_STL_Geometry * geom, +NGLIB_API void Ng_STL_AddTriangle (Ng_STL_Geometry * geom, double * p1, double * p2, double * p3, double * nv = NULL); // add (optional) edges : -DLL_HEADER void Ng_STL_AddEdge (Ng_STL_Geometry * geom, +NGLIB_API void Ng_STL_AddEdge (Ng_STL_Geometry * geom, double * p1, double * p2); // after adding triangles (and edges) initialize -DLL_HEADER Ng_Result Ng_STL_InitSTLGeometry (Ng_STL_Geometry * geom); +NGLIB_API Ng_Result Ng_STL_InitSTLGeometry (Ng_STL_Geometry * geom); // automatically generates edges: -DLL_HEADER Ng_Result Ng_STL_MakeEdges (Ng_STL_Geometry * geom, +NGLIB_API Ng_Result Ng_STL_MakeEdges (Ng_STL_Geometry * geom, Ng_Mesh* mesh, Ng_Meshing_Parameters * mp); // generates mesh, empty mesh must be already created. -DLL_HEADER Ng_Result Ng_STL_GenerateSurfaceMesh (Ng_STL_Geometry * geom, +NGLIB_API Ng_Result Ng_STL_GenerateSurfaceMesh (Ng_STL_Geometry * geom, Ng_Mesh * mesh, Ng_Meshing_Parameters * mp); @@ -638,10 +638,10 @@ DLL_HEADER Ng_Result Ng_STL_GenerateSurfaceMesh (Ng_STL_Geometry * geom, typedef void * Ng_ACIS_Geometry; // loads geometry from STL file -DLL_HEADER Ng_ACIS_Geometry * Ng_ACIS_LoadGeometry (const char * filename); +NGLIB_API Ng_ACIS_Geometry * Ng_ACIS_LoadGeometry (const char * filename); // generates mesh, empty mesh must be already created. -DLL_HEADER Ng_Result Ng_ACIS_GenerateSurfaceMesh (Ng_ACIS_Geometry * geom, +NGLIB_API Ng_Result Ng_ACIS_GenerateSurfaceMesh (Ng_ACIS_Geometry * geom, Ng_Mesh * mesh, Ng_Meshing_Parameters * mp); @@ -657,37 +657,37 @@ DLL_HEADER Ng_Result Ng_ACIS_GenerateSurfaceMesh (Ng_ACIS_Geometry * geom, // ********************************************************** // Create new OCC Geometry Object -DLL_HEADER Ng_OCC_Geometry * Ng_OCC_NewGeometry (); +NGLIB_API Ng_OCC_Geometry * Ng_OCC_NewGeometry (); // Delete an OCC Geometry Object -DLL_HEADER Ng_Result Ng_OCC_DeleteGeometry (Ng_OCC_Geometry * geom); +NGLIB_API Ng_Result Ng_OCC_DeleteGeometry (Ng_OCC_Geometry * geom); // Loads geometry from STEP file -DLL_HEADER Ng_OCC_Geometry * Ng_OCC_Load_STEP (const char * filename); +NGLIB_API Ng_OCC_Geometry * Ng_OCC_Load_STEP (const char * filename); // Loads geometry from IGES file -DLL_HEADER Ng_OCC_Geometry * Ng_OCC_Load_IGES (const char * filename); +NGLIB_API Ng_OCC_Geometry * Ng_OCC_Load_IGES (const char * filename); // Loads geometry from BREP file -DLL_HEADER Ng_OCC_Geometry * Ng_OCC_Load_BREP (const char * filename); +NGLIB_API Ng_OCC_Geometry * Ng_OCC_Load_BREP (const char * filename); // Set the local mesh size based on geometry / topology -DLL_HEADER Ng_Result Ng_OCC_SetLocalMeshSize (Ng_OCC_Geometry * geom, +NGLIB_API Ng_Result Ng_OCC_SetLocalMeshSize (Ng_OCC_Geometry * geom, Ng_Mesh * mesh, Ng_Meshing_Parameters * mp); // Mesh the edges and add Face descriptors to prepare for surface meshing -DLL_HEADER Ng_Result Ng_OCC_GenerateEdgeMesh (Ng_OCC_Geometry * geom, +NGLIB_API Ng_Result Ng_OCC_GenerateEdgeMesh (Ng_OCC_Geometry * geom, Ng_Mesh * mesh, Ng_Meshing_Parameters * mp); // Mesh the surfaces of an OCC geometry -DLL_HEADER Ng_Result Ng_OCC_GenerateSurfaceMesh (Ng_OCC_Geometry * geom, +NGLIB_API Ng_Result Ng_OCC_GenerateSurfaceMesh (Ng_OCC_Geometry * geom, Ng_Mesh * mesh, Ng_Meshing_Parameters * mp); // Get the face map of an already loaded OCC geometry -DLL_HEADER Ng_Result Ng_OCC_GetFMap(Ng_OCC_Geometry * geom, +NGLIB_API Ng_Result Ng_OCC_GetFMap(Ng_OCC_Geometry * geom, Ng_OCC_TopTools_IndexedMapOfShape * FMap); #endif // OCCGEOMETRY @@ -699,22 +699,22 @@ DLL_HEADER Ng_Result Ng_OCC_GetFMap(Ng_OCC_Geometry * geom, // ********************************************************** // uniform mesh refinement -DLL_HEADER void Ng_Uniform_Refinement (Ng_Mesh * mesh); +NGLIB_API void Ng_Uniform_Refinement (Ng_Mesh * mesh); // uniform mesh refinement with geometry adaption: -DLL_HEADER void Ng_2D_Uniform_Refinement (Ng_Geometry_2D * geom, +NGLIB_API void Ng_2D_Uniform_Refinement (Ng_Geometry_2D * geom, Ng_Mesh * mesh); -DLL_HEADER void Ng_STL_Uniform_Refinement (Ng_STL_Geometry * geom, +NGLIB_API void Ng_STL_Uniform_Refinement (Ng_STL_Geometry * geom, Ng_Mesh * mesh); -DLL_HEADER void Ng_CSG_Uniform_Refinement (Ng_CSG_Geometry * geom, +NGLIB_API void Ng_CSG_Uniform_Refinement (Ng_CSG_Geometry * geom, Ng_Mesh * mesh); #ifdef OCCGEOMETRY -DLL_HEADER void Ng_OCC_Uniform_Refinement (Ng_OCC_Geometry * geom, +NGLIB_API void Ng_OCC_Uniform_Refinement (Ng_OCC_Geometry * geom, Ng_Mesh * mesh); #endif @@ -725,22 +725,22 @@ DLL_HEADER void Ng_OCC_Uniform_Refinement (Ng_OCC_Geometry * geom, // ********************************************************** // convert mesh to second order -DLL_HEADER void Ng_Generate_SecondOrder (Ng_Mesh * mesh); +NGLIB_API void Ng_Generate_SecondOrder (Ng_Mesh * mesh); // convert mesh to second order with geometry adaption: -DLL_HEADER void Ng_2D_Generate_SecondOrder (Ng_Geometry_2D * geom, +NGLIB_API void Ng_2D_Generate_SecondOrder (Ng_Geometry_2D * geom, Ng_Mesh * mesh); -DLL_HEADER void Ng_STL_Generate_SecondOrder (Ng_STL_Geometry * geom, +NGLIB_API void Ng_STL_Generate_SecondOrder (Ng_STL_Geometry * geom, Ng_Mesh * mesh); -DLL_HEADER void Ng_CSG_Generate_SecondOrder (Ng_CSG_Geometry * geom, +NGLIB_API void Ng_CSG_Generate_SecondOrder (Ng_CSG_Geometry * geom, Ng_Mesh * mesh); #ifdef OCCGEOMETRY -DLL_HEADER void Ng_OCC_Generate_SecondOrder (Ng_OCC_Geometry * geom, +NGLIB_API void Ng_OCC_Generate_SecondOrder (Ng_OCC_Geometry * geom, Ng_Mesh * mesh); #endif diff --git a/nglib/parallelfunc.cpp b/nglib/parallelfunc.cpp index 920ed11b..0a0a445a 100644 --- a/nglib/parallelfunc.cpp +++ b/nglib/parallelfunc.cpp @@ -27,7 +27,7 @@ void Parallel_Exit(); namespace netgen { extern AutoPtr mesh; // extern VisualSceneMesh vsmesh; - extern DLL_HEADER MeshingParameters mparam; + extern NGLIB_API MeshingParameters mparam; } using namespace netgen; From fede8b4d253af60233877927f924ce8219a833d7 Mon Sep 17 00:00:00 2001 From: Joachim Schoeberl Date: Fri, 19 Feb 2021 01:28:19 +0100 Subject: [PATCH 338/384] intermediate faces --- libsrc/meshing/topology.cpp | 107 ++++++++++++++++++++++++++++++++---- 1 file changed, 95 insertions(+), 12 deletions(-) diff --git a/libsrc/meshing/topology.cpp b/libsrc/meshing/topology.cpp index 7502091a..ec54fcc3 100644 --- a/libsrc/meshing/topology.cpp +++ b/libsrc/meshing/topology.cpp @@ -917,7 +917,48 @@ namespace netgen for (int i = 0; i < face2vert.Size(); i++) vert2oldface.AddSave (face2vert[i][0], i); + // find all potential intermediate faces + Array> intermediate_faces; + if (build_parent_faces) + { + for (ElementIndex ei = 0; ei < ne; ei++) + for (int i = 0; i < 4; i++) + { + Element2d face; + // cout << "element: " << (*mesh)[ei].PNums() << endl; + (*mesh)[ei].GetFace(i+1, face); + // cout << "face " << face.PNums() << endl; + INT<3,PointIndex> f3 = { face[0], face[1], face[2] }; + for (int j = 0; j < 3; j++) + { + PointIndex v = f3[j]; + if (v >= mesh->mlbetweennodes.Size()+PointIndex::BASE) + continue; + auto pa = mesh->mlbetweennodes[v]; + for (int k = 0; k < 2; k++) + if (f3.Contains(pa[k])) + { + PointIndex v0 = pa[k]; // also in face + PointIndex v1 = pa[1-k]; + PointIndex v2 = f3[0]+f3[1]+f3[2] - v - v0; + INT<3> cf3 = { v0, v1, v2 }; + cf3.Sort(); + // cout << "intermediate: " << cf3 << " of " << f3 << endl; + intermediate_faces.Append (cf3); + } + } + } + } + cnt = 0; + for (int i = 0; i < intermediate_faces.Size(); i++) + cnt[intermediate_faces[i][0]]++; + TABLE vert2intermediate(cnt); + for (int i = 0; i < intermediate_faces.Size(); i++) + vert2intermediate.AddSave (intermediate_faces[i][0], i); + // cout << "vert2intermediate = " << endl << vert2intermediate << endl; + + for (int elnr = 0; elnr < ne; elnr++) for (int j = 0; j < 6; j++) faces[elnr][j].fnr = -1; @@ -936,7 +977,7 @@ namespace netgen // NgProfiler::StopTimer (timer2a); // NgProfiler::StartTimer (timer2b); - INDEX_3_CLOSED_HASHTABLE vert2face(2*max_face_on_vertex+10); + // INDEX_3_CLOSED_HASHTABLE vert2face(2*max_face_on_vertex+10); int oldnfa = face2vert.Size(); @@ -965,6 +1006,20 @@ namespace netgen vert2face.Set (face, 33); // something } int cnti = 0; + + for (int j = 0; j < vert2intermediate[v].Size(); j++) + { + int fnr = vert2intermediate[v][j]; + INDEX_3 face (intermediate_faces[fnr][0], + intermediate_faces[fnr][1], + intermediate_faces[fnr][2]); + face.Sort(); + if (!vert2face.Used(face)) + { + cnti++; + vert2face.Set (face, 33); // something + } + } LoopOverFaces (*mesh, *this, v, [&] (INDEX_4 i4, int elnr, int j, bool volume, int facedir) { @@ -1017,6 +1072,25 @@ namespace netgen vert2face.Set (face, fnr); } + for (int j = 0; j < vert2intermediate[v].Size(); j++) + { + int fnr = vert2intermediate[v][j]; + INDEX_3 face (intermediate_faces[fnr][0], + intermediate_faces[fnr][1], + intermediate_faces[fnr][2]); + face.Sort(); + if (!vert2face.Used(face)) + { + INDEX_4 i4(face.I1(), face.I2(), face.I3(), 0); + face2vert[nfa] = i4; + vert2face.Set (face, nfa); + nfa++; + // cout << "adding face " << i4 << endl; + // cnti++; + // vert2face.Set (face, 33); // something + } + } + LoopOverFaces (*mesh, *this, v, [&] (INDEX_4 i4, int elnr, int j, bool volume, int facedir) { @@ -1461,7 +1535,7 @@ namespace netgen { // tets only cout << "build face hierarchy:" << endl; - cout << "f2v = " << face2vert << endl; + // cout << "f2v = " << face2vert << endl; ngcore::ClosedHashTable, int> v2f(nv); for (auto i : Range(face2vert)) @@ -1472,10 +1546,10 @@ namespace netgen v2f[f3] = i; } - cout << "v2f:" << endl << v2f << endl; + // cout << "v2f:" << endl << v2f << endl; // build edge2vert hashtable - cout << "e2v = " << edge2vert << endl; + // cout << "e2v = " << edge2vert << endl; ngcore::ClosedHashTable, int> v2e(nv); for (auto i : Range(edge2vert)) @@ -1486,7 +1560,7 @@ namespace netgen v2e[e2] = i; } - cout << "v2e:" << endl << v2e << endl; + // cout << "v2e:" << endl << v2e << endl; parent_faces.SetSize (nfa); parent_faces = { -1, { -1, -1, -1, -1 } }; @@ -1530,9 +1604,13 @@ namespace netgen if (v2f.Used(parentverts)) { int pafacenr = v2f[parentverts]; - cout << "parent-face = " << pafacenr << endl; + // cout << "parent-face = " << pafacenr << endl; parent_faces[i] = { classnr, { pafacenr, -1, -1, -1 } }; } + else + { + cout << "missing parent face: " << parentverts << endl; + } issplit=true; break; } @@ -1586,25 +1664,30 @@ namespace netgen if (v2f.Used(parentverts1)) { pafacenr1 = v2f[parentverts1]; - cout << "parent-face1 = " << pafacenr1<< endl ; + // cout << "parent-face1 = " << pafacenr1<< endl ; } if (v2f.Used(parentverts2)) { pafacenr2 = v2f[parentverts2]; - cout << "parent-face2 = " << pafacenr2<< endl ; + // cout << "parent-face2 = " << pafacenr2<< endl ; } if (v2f.Used(parentverts3)) { pafacenr3 = v2f[parentverts3]; - cout << "parent-face3 = " << pafacenr3<< endl ; + // cout << "parent-face3 = " << pafacenr3<< endl ; } if (v2f.Used(parentverts4)) { pafacenr4 = v2f[parentverts4]; - cout << "parent-face4 = " << pafacenr4<< endl ; + // cout << "parent-face4 = " << pafacenr4<< endl ; } - parent_faces[i] = { classnr, { pafacenr1, pafacenr2, pafacenr3, - pafacenr4} }; + + if (k == 0 || k == 2) + parent_faces[i] = { classnr, { pafacenr2, pafacenr1, + pafacenr4, pafacenr3} }; + else + parent_faces[i] = { classnr, { pafacenr2, pafacenr1, + pafacenr3, pafacenr4} }; break; } } From 4592bf90a875a9865b786974d7d78936c10175f1 Mon Sep 17 00:00:00 2001 From: Joachim Schoeberl Date: Fri, 19 Feb 2021 02:12:58 +0100 Subject: [PATCH 339/384] subdivided faces are now working (boundary looks good) --- libsrc/meshing/topology.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/libsrc/meshing/topology.cpp b/libsrc/meshing/topology.cpp index ec54fcc3..c3729a8e 100644 --- a/libsrc/meshing/topology.cpp +++ b/libsrc/meshing/topology.cpp @@ -1571,15 +1571,14 @@ namespace netgen // find a vertex, such that one of its parent is a trig vertex + bool issplit = false; for (int k = 0; k < 3; k++) { PointIndex vb = f3[k]; // assume vb as the new bisect vert - if (vb >= mesh->mlbetweennodes.Size()+PointIndex::BASE) continue; auto parents = mesh->mlbetweennodes[vb]; - bool issplit=false; // is face part of one parent face (boundary-face) ? for (int j = 0; j < 2; j++) { @@ -1594,7 +1593,6 @@ namespace netgen INT<3> parentverts(v0, v1, v2); parentverts.Sort(); - int classnr = 0; if (v2 > vb) { Swap (v2, vb); classnr += 1; } if (v0 > v1) { Swap (v0, v1); classnr += 2; } @@ -1615,8 +1613,16 @@ namespace netgen break; } } - // is face a new face (bisect-face) ? - if (!issplit){ + } + // is face a new face (bisect-face) ? + if (!issplit) + for (int k = 0; k < 3; k++) + { + PointIndex vb = f3[k]; // assume vb as the new bisect vert + if (vb >= mesh->mlbetweennodes.Size()+PointIndex::BASE) + continue; + auto parents = mesh->mlbetweennodes[vb]; + PointIndex v0 = parents[0]; PointIndex v1 = parents[1]; PointIndex v2 = f3[(k+1)%3]; @@ -1691,7 +1697,6 @@ namespace netgen break; } } - } } } } From a354bf9e511756f51f5bff217f83eb25fa790b75 Mon Sep 17 00:00:00 2001 From: Joachim Schoeberl Date: Fri, 19 Feb 2021 10:04:45 +0100 Subject: [PATCH 340/384] bisect face classification by permutation of 5 --- libsrc/meshing/topology.cpp | 100 +++++++++++++++++++++++++++++++++++- 1 file changed, 99 insertions(+), 1 deletion(-) diff --git a/libsrc/meshing/topology.cpp b/libsrc/meshing/topology.cpp index c3729a8e..1a87722a 100644 --- a/libsrc/meshing/topology.cpp +++ b/libsrc/meshing/topology.cpp @@ -1569,8 +1569,23 @@ namespace netgen { INT<3,PointIndex> f3(face2vert[i][0], face2vert[i][1], face2vert[i][2]); - // find a vertex, such that one of its parent is a trig vertex + // face on coarses level ? + bool all_vert_coarse = true; + for (int k = 0; k < 3; k++) + { + PointIndex vb = f3[k]; + if (vb >= mesh->mlbetweennodes.Size()+PointIndex::BASE) + continue; + auto parents = mesh->mlbetweennodes[vb]; + if (parents[0] >= PointIndex::BASE) + all_vert_coarse = false; + } + if (all_vert_coarse) continue; + + + + // find a vertex, such that one of its parent is a trig vertex bool issplit = false; for (int k = 0; k < 3; k++) { @@ -1614,6 +1629,8 @@ namespace netgen } } } + + /* // is face a new face (bisect-face) ? if (!issplit) for (int k = 0; k < 3; k++) @@ -1697,6 +1714,87 @@ namespace netgen break; } } + */ + + // is face a new face (bisect-face) ? + if (!issplit) + for (int k = 0; k < 3; k++) + { + PointIndex vb = f3[k]; // assume vb as the new bisect vert + if (vb >= mesh->mlbetweennodes.Size()+PointIndex::BASE) + continue; + auto parents = mesh->mlbetweennodes[vb]; + + PointIndex v0 = parents[0]; + PointIndex v1 = parents[1]; + PointIndex v2 = f3[(k+1)%3]; + PointIndex v3 = f3[(k+2)%3]; + INT<2> parentedge1(v0, v2); + parentedge1.Sort(); + INT<2> parentedge2(v0, v3); + parentedge2.Sort(); + INT<2> parentedge3(v1, v2); + parentedge3.Sort(); + INT<2> parentedge4(v1, v3); + parentedge4.Sort(); + + // if edges [v0,v2], [v0, v3], [v1,v2], [v1,v3] exists + // then vb is the bisecting edge + if (v2e.Used(parentedge1) && v2e.Used(parentedge2) + && v2e.Used(parentedge3) && v2e.Used(parentedge4)) + { + int verts[5] = { v0, v1, v2, v3, vb }; + /* + cout << "verts5: "; + for (int j = 0; j < 5; j++) + cout << verts[j] << " "; + */ + // classify permutation of verts + int classnr = 0; + for (int j = 0; j < 4; j++) + { + int maxk = 0; + for (int k = 0; k < 5-j; k++) + if (verts[k] > verts[maxk]) maxk = k; + // compress + for (int k = maxk; k < 4-j; k++) + verts[k] = verts[k+1]; + classnr = maxk + (5-j) * classnr; + } + // cout << "classnr = " << classnr << endl; + + INT<3> parentverts1(v1, v2, v3); + parentverts1.Sort(); + INT<3> parentverts2(v0, v2, v3); + parentverts2.Sort(); + INT<3> parentverts3(v0, v1, v3); + parentverts3.Sort(); + INT<3> parentverts4(v0, v1, v2); + parentverts4.Sort(); + + if (!v2f.Used(parentverts1) || !v2f.Used(parentverts2) || + !v2f.Used(parentverts3) || !v2f.Used(parentverts4)) + { + cout << "all edges are used, but not faces ????" << endl; + continue; + } + + int pafacenr1 = v2f[parentverts1]; + int pafacenr2 = v2f[parentverts2]; + int pafacenr3 = v2f[parentverts3]; + int pafacenr4 = v2f[parentverts4]; + + + parent_faces[i] = { classnr, { pafacenr1, pafacenr2, + pafacenr3, pafacenr4} }; + + break; + } + } + + auto [info, nrs] = parent_faces[i]; + if (nrs[0] == -1) + cout << "************************** unhandled parent-face case **********************" << endl; } } } From 28c4b7841043f9136dc04699932515f757249142 Mon Sep 17 00:00:00 2001 From: Joachim Schoeberl Date: Fri, 19 Feb 2021 15:06:13 +0100 Subject: [PATCH 341/384] mesh bisection with onlyonce option. otherwise, tet-bisection performs three bisection steps to obtain h/2 --- libsrc/include/nginterface_v2.hpp | 2 +- libsrc/interface/nginterface_v2.cpp | 3 ++- libsrc/meshing/bisect.cpp | 6 +++--- libsrc/meshing/bisect.hpp | 1 + 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/libsrc/include/nginterface_v2.hpp b/libsrc/include/nginterface_v2.hpp index f2f9734b..3cf00fc8 100644 --- a/libsrc/include/nginterface_v2.hpp +++ b/libsrc/include/nginterface_v2.hpp @@ -347,7 +347,7 @@ namespace netgen void EnableTable (string name, bool set); - void Refine (NG_REFINEMENT_TYPE reftype, + void Refine (NG_REFINEMENT_TYPE reftype, bool onlyonce, void (*taskmanager)(function) = &DummyTaskManager2, void (*tracer)(string, bool) = &DummyTracer2); diff --git a/libsrc/interface/nginterface_v2.cpp b/libsrc/interface/nginterface_v2.cpp index 0f3f48a9..e417be3c 100644 --- a/libsrc/interface/nginterface_v2.cpp +++ b/libsrc/interface/nginterface_v2.cpp @@ -1156,7 +1156,7 @@ namespace netgen mesh->VolumeElement(elnr+1).SetRefinementFlag(flag); } - void Ngx_Mesh :: Refine (NG_REFINEMENT_TYPE reftype, + void Ngx_Mesh :: Refine (NG_REFINEMENT_TYPE reftype, bool onlyonce, void (*task_manager)(function), NgTracer tracer) { @@ -1166,6 +1166,7 @@ namespace netgen biopt.usemarkedelements = 1; biopt.refine_p = 0; biopt.refine_hp = 0; + biopt.onlyonce = onlyonce; if (reftype == NG_REFINE_P) biopt.refine_p = 1; if (reftype == NG_REFINE_HP) diff --git a/libsrc/meshing/bisect.cpp b/libsrc/meshing/bisect.cpp index 5127c439..0205cc81 100644 --- a/libsrc/meshing/bisect.cpp +++ b/libsrc/meshing/bisect.cpp @@ -3019,7 +3019,7 @@ namespace netgen { cnttet++; mtets.Elem(cnttet).marked = - 3 * mesh.VolumeElement(i).TestRefinementFlag(); + (opt.onlyonce ? 3 : 1) * mesh.VolumeElement(i).TestRefinementFlag(); if (mtets.Elem(cnttet).marked) cntm++; } @@ -3038,7 +3038,7 @@ namespace netgen for (int i = 1; i <= mtets.Size(); i++) { mtets.Elem(i).marked = - 3 * mesh.VolumeElement(i).TestRefinementFlag(); + (opt.onlyonce ? 1 : 3) * mesh.VolumeElement(i).TestRefinementFlag(); if (mtets.Elem(i).marked) cntm++; } @@ -3068,7 +3068,7 @@ namespace netgen { cnttrig++; mtris.Elem(cnttrig).marked = - mesh.SurfaceElement(i).TestRefinementFlag() ? 2 : 0; + mesh.SurfaceElement(i).TestRefinementFlag() ? (opt.onlyonce ? 1 : 2) : 0; // mtris.Elem(cnttrig).marked = 0; if (mtris.Elem(cnttrig).marked) cntm++; diff --git a/libsrc/meshing/bisect.hpp b/libsrc/meshing/bisect.hpp index 16849227..9cab3ef3 100644 --- a/libsrc/meshing/bisect.hpp +++ b/libsrc/meshing/bisect.hpp @@ -12,6 +12,7 @@ public: int usemarkedelements; bool refine_hp; bool refine_p; + bool onlyonce = false; NgTaskManager task_manager = &DummyTaskManager; NgTracer tracer = &DummyTracer; DLL_HEADER BisectionOptions (); From 5cc42f040deba198d1e0f5752a95cf8657bdc0a6 Mon Sep 17 00:00:00 2001 From: Joachim Schoeberl Date: Fri, 19 Feb 2021 18:20:22 +0100 Subject: [PATCH 342/384] fixing face refinement (by Guosheng) --- libsrc/meshing/topology.cpp | 71 +++++++++++++++++++++---------------- 1 file changed, 40 insertions(+), 31 deletions(-) diff --git a/libsrc/meshing/topology.cpp b/libsrc/meshing/topology.cpp index 1a87722a..07f242fb 100644 --- a/libsrc/meshing/topology.cpp +++ b/libsrc/meshing/topology.cpp @@ -890,7 +890,18 @@ namespace netgen } + // edge hashtable:: needed for getting parent faces + ngcore::ClosedHashTable, int> v2e(nv); + if (build_parent_faces) + for (auto i : Range(edge2vert)) + { + auto edge = edge2vert[i]; + INT<2> e2(edge[0], edge[1]); + e2.Sort(); + v2e[e2] = i; + } + // generate faces if (buildfaces) { @@ -908,7 +919,7 @@ namespace netgen faces.SetSize(ne); surffaces.SetSize(nse); - + cnt = 0; for (int i = 0; i < face2vert.Size(); i++) @@ -942,10 +953,16 @@ namespace netgen PointIndex v0 = pa[k]; // also in face PointIndex v1 = pa[1-k]; PointIndex v2 = f3[0]+f3[1]+f3[2] - v - v0; - INT<3> cf3 = { v0, v1, v2 }; - cf3.Sort(); - // cout << "intermediate: " << cf3 << " of " << f3 << endl; - intermediate_faces.Append (cf3); + // if there is an edge connecting v1 and v2, accept + // the new face + INT<2> parentedge(v1, v2); + parentedge.Sort(); + if (v2e.Used(parentedge)){ + INT<3> cf3 = { v0, v1, v2 }; + cf3.Sort(); + // cout << "intermediate: " << cf3 << " of " << f3 << endl; + intermediate_faces.Append (cf3); + } } } } @@ -1548,20 +1565,6 @@ namespace netgen // cout << "v2f:" << endl << v2f << endl; - // build edge2vert hashtable - // cout << "e2v = " << edge2vert << endl; - - ngcore::ClosedHashTable, int> v2e(nv); - for (auto i : Range(edge2vert)) - { - auto edge = edge2vert[i]; - INT<3> e2(edge[0], edge[1]); - e2.Sort(); - v2e[e2] = i; - } - - // cout << "v2e:" << endl << v2e << endl; - parent_faces.SetSize (nfa); parent_faces = { -1, { -1, -1, -1, -1 } }; @@ -1604,28 +1607,34 @@ namespace netgen // the third one, on the tip PointIndex v2 = f3[0]+f3[1]+f3[2] - v0 - vb; + + // if there is an edge connecting v1 and v2, accept + // the new face + INT<2> parentedge(v1, v2); + parentedge.Sort(); + if (v2e.Used(parentedge)){ + INT<3> parentverts(v0, v1, v2); + parentverts.Sort(); - INT<3> parentverts(v0, v1, v2); - parentverts.Sort(); + int classnr = 0; + if (v2 > vb) { Swap (v2, vb); classnr += 1; } + if (v0 > v1) { Swap (v0, v1); classnr += 2; } + if (v1 > v2) { Swap (v1, v2); classnr += 4; } + if (v0 > v1) { Swap (v0, v1); classnr += 8; } - int classnr = 0; - if (v2 > vb) { Swap (v2, vb); classnr += 1; } - if (v0 > v1) { Swap (v0, v1); classnr += 2; } - if (v1 > v2) { Swap (v1, v2); classnr += 4; } - if (v0 > v1) { Swap (v0, v1); classnr += 8; } - - if (v2f.Used(parentverts)) + if (v2f.Used(parentverts)) { int pafacenr = v2f[parentverts]; // cout << "parent-face = " << pafacenr << endl; parent_faces[i] = { classnr, { pafacenr, -1, -1, -1 } }; } - else + else { cout << "missing parent face: " << parentverts << endl; } - issplit=true; - break; + issplit=true; + break; + } } } } From 298cbc25239c7b91be99199dad32fa76a7762b79 Mon Sep 17 00:00:00 2001 From: Joachim Schoeberl Date: Mon, 22 Feb 2021 08:30:00 +0100 Subject: [PATCH 343/384] less printing for face hierarchy --- libsrc/meshing/topology.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libsrc/meshing/topology.cpp b/libsrc/meshing/topology.cpp index 07f242fb..ac571be7 100644 --- a/libsrc/meshing/topology.cpp +++ b/libsrc/meshing/topology.cpp @@ -1551,7 +1551,9 @@ namespace netgen if (build_parent_faces) { // tets only - cout << "build face hierarchy:" << endl; + if (id == 0) + PrintMessage (5, "build face hierarchy"); + // cout << "f2v = " << face2vert << endl; ngcore::ClosedHashTable, int> v2f(nv); From f5432718c199d75a6d11d66d4b5ecec172c5c635 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Fri, 26 Feb 2021 12:18:43 +0100 Subject: [PATCH 344/384] Fix ImproveMesh --- libsrc/meshing/improve3.cpp | 10 +++++----- libsrc/meshing/meshclass.cpp | 6 +++--- libsrc/meshing/meshclass.hpp | 4 ++-- libsrc/meshing/smoothing3.cpp | 1 + 4 files changed, 11 insertions(+), 10 deletions(-) diff --git a/libsrc/meshing/improve3.cpp b/libsrc/meshing/improve3.cpp index 071817e3..5ae6a103 100644 --- a/libsrc/meshing/improve3.cpp +++ b/libsrc/meshing/improve3.cpp @@ -521,7 +521,7 @@ void MeshOptimize3d :: CombineImprove (Mesh & mesh, // return CombineImproveSequential(mesh, goal); - mesh.BoundaryEdge (1,2); // ensure the boundary-elements table is built + mesh.BuildBoundaryEdges(false); int np = mesh.GetNP(); int ne = mesh.GetNE(); @@ -817,7 +817,7 @@ void MeshOptimize3d :: SplitImprove (Mesh & mesh, PrintMessage (3, "SplitImprove"); (*testout) << "start SplitImprove" << "\n"; - mesh.BoundaryEdge (1,2); // ensure the boundary-elements table is built + mesh.BuildBoundaryEdges(false); ParallelFor( mesh.VolumeElements().Range(), [&] (ElementIndex ei) NETGEN_LAMBDA_INLINE { @@ -2713,7 +2713,7 @@ void MeshOptimize3d :: SwapImprove (Mesh & mesh, OPTIMIZEGOAL goal, int np = mesh.GetNP(); int ne = mesh.GetNE(); - mesh.BoundaryEdge (1,2); // ensure the boundary-elements table is built + mesh.BuildBoundaryEdges(false); auto elementsonnode = mesh.CreatePoint2ElementTable(); @@ -3932,7 +3932,7 @@ void MeshOptimize3d :: SwapImprove2 (Mesh & mesh, OPTIMIZEGOAL goal) // return SwapImprove2Sequential(mesh, goal); - mesh.BoundaryEdge (1,2); // ensure the boundary-elements table is built + mesh.BuildBoundaryEdges(false); int cnt = 0; double bad1, bad2; @@ -4177,7 +4177,7 @@ void MeshOptimize3d :: SplitImprove2 (Mesh & mesh) } }); - mesh.BoundaryEdge (1,2); // ensure the boundary-elements table is built + mesh.BuildBoundaryEdges(false); Array> split_candidates(ne); std::atomic improvement_counter(0); diff --git a/libsrc/meshing/meshclass.cpp b/libsrc/meshing/meshclass.cpp index cac7dc97..3aff354b 100644 --- a/libsrc/meshing/meshclass.cpp +++ b/libsrc/meshing/meshclass.cpp @@ -1794,12 +1794,12 @@ namespace netgen volelements.SetAllocSize(nel); } - - void Mesh :: BuildBoundaryEdges(void) + void Mesh :: BuildBoundaryEdges(bool rebuild) { static Timer t("Mesh::BuildBoundaryEdges"); RegionTimer reg(t); - // delete boundaryedges; + if(!rebuild && boundaryedges) + return; boundaryedges = make_unique> (3 * (GetNSE() + GetNOpenElements()) + GetNSeg() + 1); diff --git a/libsrc/meshing/meshclass.hpp b/libsrc/meshing/meshclass.hpp index 65ff082f..e3e61477 100644 --- a/libsrc/meshing/meshclass.hpp +++ b/libsrc/meshing/meshclass.hpp @@ -156,10 +156,10 @@ namespace netgen shared_ptr geometry; - private: - void BuildBoundaryEdges(void); public: + void BuildBoundaryEdges(bool rebuild=true); + bool PointContainedIn2DElement(const Point3d & p, double lami[3], const int element, diff --git a/libsrc/meshing/smoothing3.cpp b/libsrc/meshing/smoothing3.cpp index e84a18ba..0f8652f6 100644 --- a/libsrc/meshing/smoothing3.cpp +++ b/libsrc/meshing/smoothing3.cpp @@ -1460,6 +1460,7 @@ void Mesh :: ImproveMesh (const MeshingParameters & mp, OPTIMIZEGOAL goal) static Timer trange("range"); // return ImproveMeshSequential(mp, goal); + BuildBoundaryEdges(false); (*testout) << "Improve Mesh" << "\n"; PrintMessage (3, "ImproveMesh"); From f8aa3d31596fc39bb54d37fb24b0ae0d1a0fa780 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Mon, 1 Mar 2021 09:33:47 +0100 Subject: [PATCH 345/384] util function NotTooBad() in mesh optimization --- libsrc/meshing/improve3.cpp | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/libsrc/meshing/improve3.cpp b/libsrc/meshing/improve3.cpp index 5ae6a103..57214803 100644 --- a/libsrc/meshing/improve3.cpp +++ b/libsrc/meshing/improve3.cpp @@ -14,6 +14,12 @@ namespace netgen { +static inline bool NotTooBad(double bad1, double bad2) +{ + return (bad2 <= bad1) || + (bad2 <= 100 * bad1 && bad2 <= 1e18) || + (bad2 <= 1e8); +} // Calc badness of new element where pi1 and pi2 are replaced by pnew double CalcBadReplacePoints (const Mesh::T_POINTS & points, const MeshingParameters & mp, const Element & elem, double h, PointIndex &pi1, PointIndex &pi2, MeshPoint &pnew) @@ -1920,12 +1926,8 @@ void MeshOptimize3d :: SwapImproveSequential (Mesh & mesh, OPTIMIZEGOAL goal, if (goal == OPT_CONFORM) - // (bad2 <= 100 * bad1 || bad2 <= 1e6)) { - bool nottoobad = - (bad2 <= bad1) || - (bad2 <= 100 * bad1 && bad2 <= 1e18) || - (bad2 <= 1e8); + bool nottoobad = NotTooBad(bad1, bad2); for (int k = l+1; k <= nsuround + l - 2; k++) { @@ -2606,12 +2608,8 @@ double MeshOptimize3d :: SwapImproveEdge (Mesh & mesh, OPTIMIZEGOAL goal, if (goal == OPT_CONFORM) - // (bad2 <= 100 * bad1 || bad2 <= 1e6)) { - bool nottoobad = - (bad2 <= bad1) || - (bad2 <= 100 * bad1 && bad2 <= 1e18) || - (bad2 <= 1e8); + bool nottoobad = NotTooBad(bad1, bad2); for (int k = l+1; k <= nsuround + l - 2; k++) { From d7d12ac53d7cc0e4ac53378ffba5e8c3eb640177 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Mon, 1 Mar 2021 09:57:31 +0100 Subject: [PATCH 346/384] Don't swap very bad elements in SwapImprove Changes meshing -> new test results --- libsrc/meshing/improve3.cpp | 23 +-- tests/pytest/results.json | 292 ++++++++++++++++++------------------ 2 files changed, 159 insertions(+), 156 deletions(-) diff --git a/libsrc/meshing/improve3.cpp b/libsrc/meshing/improve3.cpp index 57214803..fe7d897d 100644 --- a/libsrc/meshing/improve3.cpp +++ b/libsrc/meshing/improve3.cpp @@ -14,6 +14,8 @@ namespace netgen { +static constexpr int IMPROVEMENT_CONFORMING_EDGE = -1e6; + static inline bool NotTooBad(double bad1, double bad2) { return (bad2 <= bad1) || @@ -2443,21 +2445,22 @@ double MeshOptimize3d :: SwapImproveEdge (Mesh & mesh, OPTIMIZEGOAL goal, bool swap2, swap3; - if (goal != OPT_CONFORM) + if (goal == OPT_CONFORM) + { + swap2 = mesh.BoundaryEdge (pi3, pi5) && NotTooBad(bad1, bad2); + swap3 = mesh.BoundaryEdge (pi4, pi6) && NotTooBad(bad1, bad3); + + if(swap2 || swap3) + d_badness = IMPROVEMENT_CONFORMING_EDGE; + } + + if (goal != OPT_CONFORM || (!swap2 && !swap3)) { swap2 = (bad2 < bad1) && (bad2 < bad3); swap3 = !swap2 && (bad3 < bad1); - } - else - { - if (mesh.BoundaryEdge (pi3, pi5)) bad2 /= 1e6; - if (mesh.BoundaryEdge (pi4, pi6)) bad3 /= 1e6; - - swap2 = (bad2 < bad1) && (bad2 < bad3); - swap3 = !swap2 && (bad3 < bad1); + d_badness = swap2 ? bad2-bad1 : bad3-bad1; } - d_badness = swap2 ? bad2-bad1 : bad3-bad1; if(check_only) return d_badness; diff --git a/tests/pytest/results.json b/tests/pytest/results.json index 74f0e308..0ece1b09 100644 --- a/tests/pytest/results.json +++ b/tests/pytest/results.json @@ -488,12 +488,12 @@ "ne2d": 164, "ne3d": 252, "quality_histogram": "[0, 0, 0, 0, 0, 0, 1, 4, 2, 3, 11, 30, 31, 34, 40, 38, 33, 17, 7, 1]", - "total_badness": 369.95189199 + "total_badness": 369.95189237 }, { "angles_tet": [ - 20.8, - 137.89 + 14.206, + 159.84 ], "angles_trig": [ 21.077, @@ -501,9 +501,9 @@ ], "ne1d": 190, "ne2d": 300, - "ne3d": 631, - "quality_histogram": "[0, 0, 0, 0, 1, 0, 0, 3, 8, 27, 48, 61, 68, 107, 85, 89, 63, 49, 20, 2]", - "total_badness": 943.22430902 + "ne3d": 632, + "quality_histogram": "[0, 0, 0, 0, 2, 0, 0, 4, 8, 26, 45, 62, 80, 96, 90, 84, 65, 46, 22, 2]", + "total_badness": 947.91494351 }, { "angles_tet": [ @@ -1258,18 +1258,18 @@ }, { "angles_tet": [ - 21.427, + 21.266, 143.66 ], "angles_trig": [ - 23.929, - 119.81 + 23.958, + 119.8 ], "ne1d": 388, "ne2d": 6142, - "ne3d": 54709, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 2, 17, 61, 251, 727, 2119, 4819, 8218, 11623, 13209, 10213, 3450]", - "total_badness": 65887.909834 + "ne3d": 54704, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 2, 17, 66, 248, 717, 2138, 4854, 8219, 11632, 13173, 10210, 3428]", + "total_badness": 65897.969985 } ], "fichera.geo": [ @@ -1284,9 +1284,9 @@ ], "ne1d": 50, "ne2d": 38, - "ne3d": 35, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 3, 8, 4, 10, 2, 0, 0, 2]", - "total_badness": 50.263302236 + "ne3d": 36, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 5, 4, 7, 6, 8, 1, 1, 0, 1]", + "total_badness": 53.038414986 }, { "angles_tet": [ @@ -1329,9 +1329,9 @@ ], "ne1d": 50, "ne2d": 38, - "ne3d": 35, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 3, 8, 4, 10, 2, 0, 0, 2]", - "total_badness": 50.263302236 + "ne3d": 36, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 5, 4, 7, 6, 8, 1, 1, 0, 1]", + "total_badness": 53.038414986 }, { "angles_tet": [ @@ -1367,7 +1367,7 @@ "frame.step": [ { "angles_tet": [ - 2.9095, + 2.9158, 171.1 ], "angles_trig": [ @@ -1376,9 +1376,9 @@ ], "ne1d": 10108, "ne2d": 30160, - "ne3d": 153012, - "quality_histogram": "[0, 3, 1, 3, 6, 20, 57, 149, 536, 1257, 2919, 5836, 10439, 16388, 21788, 26067, 26565, 22916, 14350, 3712]", - "total_badness": 202656.25887 + "ne3d": 152932, + "quality_histogram": "[0, 3, 1, 3, 6, 20, 60, 151, 543, 1312, 2940, 5874, 10445, 16338, 21809, 26075, 26405, 22854, 14351, 3742]", + "total_badness": 202658.67088 }, { "angles_tet": [ @@ -1391,13 +1391,13 @@ ], "ne1d": 5988, "ne2d": 11102, - "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 + "ne3d": 29140, + "quality_histogram": "[3, 4, 3, 10, 18, 43, 114, 248, 669, 1026, 1563, 2467, 3073, 3886, 4389, 4179, 3406, 2403, 1317, 319]", + "total_badness": 43201.580215 }, { "angles_tet": [ - 2.5792, + 2.1788, 174.11 ], "angles_trig": [ @@ -1406,16 +1406,16 @@ ], "ne1d": 9622, "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.5334 + "ne3d": 80884, + "quality_histogram": "[2, 15, 4, 18, 16, 39, 98, 222, 478, 1114, 2389, 4532, 7510, 10291, 12685, 13114, 12137, 9102, 5641, 1477]", + "total_badness": 111769.66842 } ], "hinge.stl": [ { "angles_tet": [ - 21.248, - 144.42 + 16.835, + 148.75 ], "angles_trig": [ 18.101, @@ -1423,9 +1423,9 @@ ], "ne1d": 456, "ne2d": 1220, - "ne3d": 1986, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 8, 20, 39, 66, 127, 177, 243, 307, 299, 259, 259, 141, 41]", - "total_badness": 2751.3290713 + "ne3d": 1985, + "quality_histogram": "[0, 0, 0, 0, 0, 1, 0, 9, 20, 38, 65, 129, 172, 240, 303, 297, 268, 263, 138, 42]", + "total_badness": 2749.9093553 }, { "angles_tet": [ @@ -1438,9 +1438,9 @@ ], "ne1d": 298, "ne2d": 610, - "ne3d": 788, - "quality_histogram": "[0, 0, 1, 10, 9, 4, 22, 15, 39, 41, 68, 84, 103, 97, 84, 85, 48, 49, 25, 4]", - "total_badness": 1361.2509309 + "ne3d": 789, + "quality_histogram": "[0, 0, 1, 10, 9, 4, 22, 15, 40, 43, 68, 84, 103, 96, 83, 85, 48, 49, 25, 4]", + "total_badness": 1364.9012739 }, { "angles_tet": [ @@ -1453,9 +1453,9 @@ ], "ne1d": 370, "ne2d": 856, - "ne3d": 1135, - "quality_histogram": "[0, 0, 0, 2, 4, 5, 14, 26, 39, 57, 79, 117, 135, 136, 153, 151, 97, 67, 45, 8]", - "total_badness": 1799.6066426 + "ne3d": 1134, + "quality_histogram": "[0, 0, 0, 2, 4, 5, 14, 25, 38, 56, 78, 119, 136, 137, 152, 151, 98, 66, 45, 8]", + "total_badness": 1795.6519937 }, { "angles_tet": [ @@ -1468,9 +1468,9 @@ ], "ne1d": 516, "ne2d": 1574, - "ne3d": 2598, - "quality_histogram": "[0, 0, 0, 0, 0, 4, 3, 4, 26, 48, 95, 172, 225, 326, 383, 383, 339, 325, 216, 49]", - "total_badness": 3605.8538311 + "ne3d": 2592, + "quality_histogram": "[0, 0, 0, 0, 0, 4, 3, 4, 24, 49, 98, 174, 224, 322, 378, 396, 333, 317, 216, 50]", + "total_badness": 3599.8559259 }, { "angles_tet": [ @@ -1483,9 +1483,9 @@ ], "ne1d": 722, "ne2d": 2866, - "ne3d": 6700, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 1, 2, 22, 29, 52, 170, 325, 637, 877, 1046, 1169, 1237, 870, 263]", - "total_badness": 8579.1803793 + "ne3d": 6672, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 1, 1, 24, 30, 67, 169, 331, 632, 870, 1040, 1173, 1200, 874, 260]", + "total_badness": 8558.9452401 }, { "angles_tet": [ @@ -1498,9 +1498,9 @@ ], "ne1d": 1862, "ne2d": 19474, - "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 + "ne3d": 136547, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 1, 8, 60, 274, 868, 2525, 6456, 12982, 21266, 29083, 31162, 24018, 7844]", + "total_badness": 165951.25229 } ], "lense.in2d": [ @@ -1729,9 +1729,9 @@ ], "ne1d": 4106, "ne2d": 27994, - "ne3d": 70797, - "quality_histogram": "[0, 0, 0, 1, 30, 72, 170, 340, 665, 1450, 2605, 4080, 6678, 9294, 10482, 10758, 9889, 7627, 4870, 1786]", - "total_badness": 99064.519397 + "ne3d": 70789, + "quality_histogram": "[0, 0, 0, 1, 31, 72, 171, 344, 668, 1440, 2602, 4089, 6675, 9290, 10472, 10751, 9903, 7620, 4876, 1784]", + "total_badness": 99059.754776 } ], "manyholes2.geo": [ @@ -1747,8 +1747,8 @@ "ne1d": 10202, "ne2d": 55380, "ne3d": 128239, - "quality_histogram": "[0, 0, 0, 0, 4, 29, 79, 237, 724, 1933, 4439, 7719, 11694, 17428, 18585, 18328, 17275, 15160, 10938, 3667]", - "total_badness": 176224.09669 + "quality_histogram": "[0, 0, 0, 0, 4, 28, 79, 241, 721, 1932, 4433, 7722, 11698, 17421, 18591, 18340, 17271, 15154, 10934, 3670]", + "total_badness": 176223.54068 } ], "matrix.geo": [ @@ -1938,18 +1938,18 @@ "part1.stl": [ { "angles_tet": [ - 13.213, - 147.22 + 14.209, + 147.23 ], "angles_trig": [ 19.94, - 128.03 + 127.49 ], "ne1d": 170, "ne2d": 448, - "ne3d": 1260, - "quality_histogram": "[0, 0, 0, 0, 0, 2, 2, 9, 17, 21, 37, 69, 106, 152, 209, 198, 165, 149, 98, 26]", - "total_badness": 1750.899754 + "ne3d": 1261, + "quality_histogram": "[0, 0, 0, 0, 0, 1, 3, 8, 15, 25, 35, 78, 97, 157, 211, 199, 161, 144, 100, 27]", + "total_badness": 1752.4668505 }, { "angles_tet": [ @@ -1962,43 +1962,43 @@ ], "ne1d": 134, "ne2d": 288, - "ne3d": 528, - "quality_histogram": "[0, 0, 0, 2, 4, 2, 4, 3, 16, 24, 36, 42, 54, 69, 66, 74, 61, 46, 24, 1]", - "total_badness": 813.76674756 + "ne3d": 524, + "quality_histogram": "[0, 0, 0, 2, 4, 2, 4, 7, 16, 28, 38, 46, 52, 62, 72, 70, 55, 40, 24, 2]", + "total_badness": 820.9371699 }, { "angles_tet": [ - 20.704, - 143.31 + 21.121, + 143.15 ], "angles_trig": [ - 24.375, + 24.417, 116.27 ], "ne1d": 194, "ne2d": 594, "ne3d": 1693, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 1, 5, 14, 28, 54, 137, 197, 250, 262, 308, 248, 149, 40]", - "total_badness": 2242.4690855 + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 1, 5, 3, 28, 53, 113, 172, 250, 278, 293, 284, 173, 40]", + "total_badness": 2213.1235108 }, { "angles_tet": [ - 22.052, - 141.32 + 22.044, + 141.38 ], "angles_trig": [ - 25.868, - 119.75 + 25.297, + 120.13 ], "ne1d": 266, "ne2d": 986, - "ne3d": 4101, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 5, 12, 29, 53, 158, 292, 530, 683, 826, 812, 568, 133]", - "total_badness": 5160.0364225 + "ne3d": 4106, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 1, 5, 11, 28, 57, 139, 316, 492, 706, 817, 813, 570, 151]", + "total_badness": 5157.0222907 }, { "angles_tet": [ - 23.306, + 23.336, 138.08 ], "angles_trig": [ @@ -2007,9 +2007,9 @@ ], "ne1d": 674, "ne2d": 6854, - "ne3d": 82748, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 1, 3, 17, 121, 417, 1362, 3669, 7623, 12797, 17700, 19603, 14878, 4557]", - "total_badness": 100231.59467 + "ne3d": 82721, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 1, 3, 16, 118, 414, 1347, 3658, 7624, 12768, 17708, 19580, 14908, 4576]", + "total_badness": 100175.28811 } ], "period.geo": [ @@ -2116,9 +2116,9 @@ ], "ne1d": 886, "ne2d": 2592, - "ne3d": 8269, - "quality_histogram": "[4, 9, 33, 44, 40, 53, 44, 46, 101, 142, 258, 402, 641, 938, 1253, 1304, 1193, 1022, 589, 153]", - "total_badness": 12315.265721 + "ne3d": 8292, + "quality_histogram": "[5, 9, 29, 46, 37, 51, 44, 46, 94, 160, 257, 412, 647, 899, 1265, 1378, 1157, 1002, 611, 143]", + "total_badness": 12343.24347 }, { "angles_tet": [ @@ -2131,24 +2131,24 @@ ], "ne1d": 570, "ne2d": 1202, - "ne3d": 1839, - "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 + "ne3d": 1795, + "quality_histogram": "[2, 20, 39, 51, 70, 80, 102, 131, 157, 158, 176, 170, 145, 140, 122, 84, 67, 50, 26, 5]", + "total_badness": 4436.3977005 }, { "angles_tet": [ 1.1033, - 172.29 + 171.77 ], "angles_trig": [ 3.728, - 163.66 + 165.5 ], "ne1d": 724, "ne2d": 1730, - "ne3d": 3267, - "quality_histogram": "[3, 15, 32, 52, 50, 38, 44, 76, 118, 161, 234, 258, 360, 375, 419, 411, 310, 195, 94, 22]", - "total_badness": 6011.5192864 + "ne3d": 3290, + "quality_histogram": "[3, 18, 29, 53, 45, 38, 53, 72, 116, 168, 230, 257, 328, 415, 424, 399, 334, 189, 92, 27]", + "total_badness": 6051.57684 }, { "angles_tet": [ @@ -2157,18 +2157,18 @@ ], "angles_trig": [ 2.0839, - 165.56 + 163.08 ], "ne1d": 956, "ne2d": 2828, - "ne3d": 8577, - "quality_histogram": "[3, 9, 37, 48, 48, 52, 57, 61, 87, 129, 205, 326, 507, 804, 1200, 1394, 1476, 1215, 736, 183]", - "total_badness": 12580.561684 + "ne3d": 8481, + "quality_histogram": "[3, 8, 38, 49, 47, 50, 55, 57, 96, 137, 195, 343, 515, 792, 1200, 1366, 1417, 1181, 742, 190]", + "total_badness": 12456.662988 }, { "angles_tet": [ - 1.3345, - 171.17 + 1.1518, + 168.3 ], "angles_trig": [ 1.7811, @@ -2176,9 +2176,9 @@ ], "ne1d": 1554, "ne2d": 6372, - "ne3d": 31607, - "quality_histogram": "[2, 7, 14, 7, 26, 53, 50, 67, 90, 188, 312, 638, 1249, 2301, 3886, 5314, 6167, 5965, 4114, 1157]", - "total_badness": 40813.948339 + "ne3d": 31605, + "quality_histogram": "[2, 8, 13, 9, 26, 53, 51, 69, 87, 191, 315, 647, 1221, 2378, 3853, 5328, 6181, 5935, 4068, 1170]", + "total_badness": 40844.172563 }, { "angles_tet": [ @@ -2191,9 +2191,9 @@ ], "ne1d": 2992, "ne2d": 23322, - "ne3d": 281896, - "quality_histogram": "[4, 10, 12, 10, 9, 21, 29, 61, 95, 246, 747, 2146, 5540, 13546, 27675, 44558, 59947, 64037, 48291, 14912]", - "total_badness": 344508.9779 + "ne3d": 281946, + "quality_histogram": "[4, 10, 12, 10, 9, 21, 29, 60, 99, 245, 724, 2133, 5538, 13549, 27663, 44504, 60069, 63936, 48457, 14874]", + "total_badness": 344547.37835 } ], "revolution.geo": [ @@ -2209,8 +2209,8 @@ "ne1d": 320, "ne2d": 3110, "ne3d": 8379, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 3, 27, 91, 210, 453, 679, 983, 1088, 1150, 1165, 1083, 812, 518, 117]", - "total_badness": 11964.310211 + "quality_histogram": "[0, 0, 0, 0, 0, 0, 3, 27, 90, 212, 461, 680, 967, 1096, 1153, 1170, 1080, 802, 520, 118]", + "total_badness": 11967.150699 }, { "angles_tet": [ @@ -2253,9 +2253,9 @@ ], "ne1d": 320, "ne2d": 3110, - "ne3d": 8253, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 2, 13, 47, 138, 333, 624, 839, 1047, 1151, 1187, 1166, 945, 608, 153]", - "total_badness": 11468.848993 + "ne3d": 8258, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 2, 13, 48, 141, 339, 627, 829, 1041, 1149, 1209, 1156, 945, 605, 154]", + "total_badness": 11481.414846 }, { "angles_tet": [ @@ -2274,18 +2274,18 @@ }, { "angles_tet": [ - 21.857, + 21.902, 143.83 ], "angles_trig": [ - 19.774, + 19.492, 121.07 ], "ne1d": 800, "ne2d": 17934, - "ne3d": 201342, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 4, 13, 87, 366, 1250, 3570, 9060, 18977, 31022, 42571, 46627, 36250, 11545]", - "total_badness": 244286.77424 + "ne3d": 201307, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 4, 11, 83, 359, 1237, 3580, 9039, 19000, 30994, 42542, 46628, 36256, 11574]", + "total_badness": 244220.94708 } ], "screw.step": [ @@ -2306,7 +2306,7 @@ }, { "angles_tet": [ - 21.55, + 19.077, 146.38 ], "angles_trig": [ @@ -2315,9 +2315,9 @@ ], "ne1d": 528, "ne2d": 2792, - "ne3d": 8129, - "quality_histogram": "[0, 0, 0, 0, 0, 1, 4, 8, 35, 96, 188, 298, 537, 817, 1057, 1323, 1446, 1284, 798, 237]", - "total_badness": 10753.086327 + "ne3d": 8126, + "quality_histogram": "[0, 0, 0, 0, 0, 1, 4, 11, 33, 98, 190, 299, 553, 796, 1040, 1329, 1446, 1294, 795, 237]", + "total_badness": 10753.750681 }, { "angles_tet": [ @@ -2330,9 +2330,9 @@ ], "ne1d": 666, "ne2d": 4922, - "ne3d": 31540, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 1, 5, 31, 92, 290, 707, 1762, 3221, 4997, 6712, 6966, 5146, 1610]", - "total_badness": 38689.280913 + "ne3d": 31546, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 1, 5, 29, 94, 294, 701, 1778, 3224, 4988, 6720, 6967, 5142, 1603]", + "total_badness": 38702.936245 } ], "sculpture.geo": [ @@ -2430,18 +2430,18 @@ "shaft.geo": [ { "angles_tet": [ - 8.3002, + 8.3078, 162.65 ], "angles_trig": [ - 9.3888, + 9.3916, 147.77 ], "ne1d": 708, "ne2d": 1722, - "ne3d": 2740, - "quality_histogram": "[0, 0, 1, 5, 8, 15, 31, 39, 87, 146, 294, 392, 329, 286, 245, 291, 247, 185, 108, 31]", - "total_badness": 4403.8888129 + "ne3d": 2734, + "quality_histogram": "[0, 0, 2, 4, 8, 15, 30, 41, 85, 143, 291, 393, 333, 284, 246, 293, 248, 190, 101, 27]", + "total_badness": 4392.4206713 }, { "angles_tet": [ @@ -2456,7 +2456,7 @@ "ne2d": 606, "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 + "total_badness": 1208.0644901 }, { "angles_tet": [ @@ -2479,14 +2479,14 @@ 162.65 ], "angles_trig": [ - 15.525, - 147.01 + 15.512, + 147.17 ], "ne1d": 708, "ne2d": 1722, - "ne3d": 2713, - "quality_histogram": "[0, 0, 0, 1, 3, 1, 11, 22, 49, 109, 260, 408, 344, 300, 273, 303, 272, 215, 106, 36]", - "total_badness": 4151.3073463 + "ne3d": 2708, + "quality_histogram": "[0, 0, 0, 1, 3, 1, 11, 22, 50, 108, 258, 412, 344, 299, 275, 311, 271, 203, 108, 31]", + "total_badness": 4149.681437 }, { "angles_tet": [ @@ -3083,9 +3083,9 @@ ], "ne1d": 690, "ne2d": 1684, - "ne3d": 5177, - "quality_histogram": "[0, 0, 1, 0, 1, 8, 27, 37, 108, 191, 285, 369, 461, 565, 670, 690, 621, 536, 462, 145]", - "total_badness": 7461.1502455 + "ne3d": 5178, + "quality_histogram": "[0, 0, 1, 0, 1, 8, 29, 37, 107, 193, 284, 368, 461, 566, 670, 689, 621, 536, 462, 145]", + "total_badness": 7465.8398023 }, { "angles_tet": [ @@ -3098,9 +3098,9 @@ ], "ne1d": 390, "ne2d": 522, - "ne3d": 1349, - "quality_histogram": "[0, 0, 4, 13, 12, 41, 78, 115, 124, 147, 169, 127, 141, 104, 86, 86, 55, 34, 11, 2]", - "total_badness": 2729.6156372 + "ne3d": 1347, + "quality_histogram": "[0, 0, 4, 14, 14, 41, 75, 117, 125, 145, 169, 126, 140, 107, 82, 87, 54, 34, 11, 2]", + "total_badness": 2735.6699238 }, { "angles_tet": [ @@ -3113,9 +3113,9 @@ ], "ne1d": 512, "ne2d": 874, - "ne3d": 2381, - "quality_histogram": "[0, 0, 0, 3, 9, 13, 41, 68, 124, 140, 196, 214, 302, 390, 345, 237, 128, 98, 47, 26]", - "total_badness": 3927.0434195 + "ne3d": 2395, + "quality_histogram": "[0, 0, 0, 3, 9, 13, 42, 68, 129, 146, 191, 209, 315, 390, 343, 236, 134, 94, 49, 24]", + "total_badness": 3955.4970644 }, { "angles_tet": [ @@ -3130,7 +3130,7 @@ "ne2d": 1684, "ne3d": 5095, "quality_histogram": "[0, 0, 1, 0, 0, 4, 19, 34, 101, 181, 263, 354, 439, 548, 689, 696, 611, 547, 467, 141]", - "total_badness": 7282.7477612 + "total_badness": 7282.7477811 }, { "angles_tet": [ @@ -3143,9 +3143,9 @@ ], "ne1d": 1050, "ne2d": 3812, - "ne3d": 18003, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 3, 15, 34, 61, 181, 573, 1428, 2189, 2298, 2700, 2707, 2735, 2389, 690]", - "total_badness": 23471.146878 + "ne3d": 18028, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 3, 15, 34, 62, 183, 573, 1437, 2190, 2345, 2680, 2713, 2701, 2419, 673]", + "total_badness": 23515.317943 }, { "angles_tet": [ @@ -3158,9 +3158,9 @@ ], "ne1d": 1722, "ne2d": 10042, - "ne3d": 84812, - "quality_histogram": "[0, 0, 0, 0, 0, 2, 49, 1423, 720, 374, 704, 1174, 2454, 5477, 8890, 13211, 16429, 16935, 12870, 4100]", - "total_badness": 108503.84867 + "ne3d": 84906, + "quality_histogram": "[0, 0, 0, 0, 0, 2, 49, 1422, 720, 370, 704, 1186, 2437, 5535, 8984, 13266, 16409, 16882, 12872, 4068]", + "total_badness": 108652.77514 } ], "twobricks.geo": [ From 3cbab4e2255bf83546bc2405d81b7a6e6dfe8e3c Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Tue, 2 Mar 2021 09:27:14 +0100 Subject: [PATCH 347/384] No write check on install dir with USE_SUPERBUILD=OFF --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7d7c284a..b7158325 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -54,14 +54,14 @@ if(INSTALL_DIR) set(INSTALL_DIR_DEFAULT ${INSTALL_DIR}) endif(INSTALL_DIR) -if(UNIX) +if(UNIX AND NOT USE_SUPERBUILD) message("Checking for write permissions in install directory...") execute_process(COMMAND mkdir -p ${CMAKE_INSTALL_PREFIX}) execute_process(COMMAND test -w ${CMAKE_INSTALL_PREFIX} RESULT_VARIABLE res) if(res) message(WARNING "No write access at install directory, please set correct permissions") endif() -endif(UNIX) +endif(UNIX AND NOT USE_SUPERBUILD) if (USE_SUPERBUILD) project (SUPERBUILD) From bfa88c88ebd67a7665d1339183c3f5db101bf4b8 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Tue, 2 Mar 2021 09:27:14 +0100 Subject: [PATCH 348/384] No write check on install dir with USE_SUPERBUILD=OFF --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7d7c284a..8e5ade9b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -54,14 +54,14 @@ if(INSTALL_DIR) set(INSTALL_DIR_DEFAULT ${INSTALL_DIR}) endif(INSTALL_DIR) -if(UNIX) +if(UNIX AND USE_SUPERBUILD) message("Checking for write permissions in install directory...") execute_process(COMMAND mkdir -p ${CMAKE_INSTALL_PREFIX}) execute_process(COMMAND test -w ${CMAKE_INSTALL_PREFIX} RESULT_VARIABLE res) if(res) message(WARNING "No write access at install directory, please set correct permissions") endif() -endif(UNIX) +endif(UNIX AND USE_SUPERBUILD) if (USE_SUPERBUILD) project (SUPERBUILD) From f11cb4fcfb9314d842d52869fe8075b2dd3732d4 Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Tue, 2 Mar 2021 11:47:40 +0100 Subject: [PATCH 349/384] boundarylayers - inner corners at end of layer now possible too --- libsrc/meshing/boundarylayer.cpp | 54 +++++++++++++++++++++--------- tests/pytest/test_boundarylayer.py | 53 ++++++++++++++++++++++++++++- 2 files changed, 91 insertions(+), 16 deletions(-) diff --git a/libsrc/meshing/boundarylayer.cpp b/libsrc/meshing/boundarylayer.cpp index d0bfe335..4539887c 100644 --- a/libsrc/meshing/boundarylayer.cpp +++ b/libsrc/meshing/boundarylayer.cpp @@ -515,28 +515,52 @@ namespace netgen { if(el.GetType() == TET) { - if(moved.Size() == 2) + if(moved.Size() == 3) // inner corner { - if(fixed.Size() == 2) - throw Exception("This should not be possible!"); PointIndex p1 = moved[0]; PointIndex p2 = moved[1]; + PointIndex p3 = moved[2]; + auto v1 = mesh[p1]; + auto n = Cross(mesh[p2]-v1, mesh[p3]-v1); + auto d = mesh[mapto[p1][0]] - v1; + if(n*d > 0) + Swap(p2,p3); + PointIndex p4 = p1; + PointIndex p5 = p2; + PointIndex p6 = p3; for(auto i : Range(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]); + Element nel(PRISM); + nel[0] = p4; nel[1] = p5; nel[2] = p6; + p4 = mapto[p1][i]; p5 = mapto[p2][i]; p6 = mapto[p3][i]; + nel[3] = p4; nel[4] = p5; nel[5] = p6; nel.SetIndex(el.GetIndex()); mesh.AddVolumeElement(nel); - p1 = p4; - p2 = p3; + } + } + if(moved.Size() == 2) + { + if(fixed.Size() == 1) + { + 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) diff --git a/tests/pytest/test_boundarylayer.py b/tests/pytest/test_boundarylayer.py index f9310955..798cb1cc 100644 --- a/tests/pytest/test_boundarylayer.py +++ b/tests/pytest/test_boundarylayer.py @@ -66,7 +66,7 @@ def test_boundarylayer2(outside, version, capfd): @pytest.mark.parametrize("outside", [True, False]) -def test_wrong_orientation(outside): +def test_wrong_orientation(outside, capfd): geo = CSGeometry() brick = OrthoBrick((-1,0,0),(1,1,1)) - Plane((0,0,0), (1,0,0)) geo.Add(brick.mat("air")) @@ -107,3 +107,54 @@ def test_pyramids(outside): 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) + +@pytest.mark.parametrize("outside", [True, False]) +def test_with_inner_corner(outside, capfd): + geo = CSGeometry() + + core_thickness = 0.1 + limb_distance = 0.5 + core_height = 0.5 + coil_r1 = 0.08 + coil_r2 = 0.16 + coil_h = 0.2 + domain_size = 1.2 + domain_size_y = 0.7 + + def CreateCoil(x): + outer = Cylinder((x, 0, -1), (x, 0, 1), coil_r2) + inner = Cylinder((x, 0, -1), (x, 0, 1), coil_r1) + top = Plane((0,0,coil_h/2), (0,0,1)) + bot = Plane((0,0,-coil_h/2), (0,0,-1)) + return ((outer - inner) * top * bot, (outer, inner, top, bot)) + + core_front = Plane((0,-core_thickness/2, 0), (0,-1,0)).bc("core_front") + core_back = Plane((0,core_thickness/2, 0), (0,1,0)).bc("core_front") + core_limb1 = OrthoBrick((-limb_distance/2-core_thickness/2, -core_thickness, -core_height/2),(-limb_distance/2+core_thickness/2, core_thickness, core_height/2)) + core_limb2 = OrthoBrick((limb_distance/2-core_thickness/2, -core_thickness, -core_height/2),(limb_distance/2+core_thickness/2, core_thickness, core_height/2)) + core_top = OrthoBrick((-limb_distance/2-core_thickness/2, -core_thickness, core_height/2-core_thickness/2),(limb_distance/2+core_thickness/2, core_thickness, core_height/2+core_thickness/2)) + core_bot = OrthoBrick((-limb_distance/2-core_thickness/2, -core_thickness, -core_height/2-core_thickness/2),(limb_distance/2+core_thickness/2, core_thickness, -core_height/2+core_thickness/2)) + + core = (core_limb1 + core_limb2 + core_top + core_bot).bc("core_rest") + core = core * core_front * core_back + core.maxh(core_thickness * 0.4) + + coil1, (outer1, inner1, top1, bot1) = CreateCoil(-limb_distance/2) + coil1.mat("coil_1") + coil2, (outer2, inner2, top2, bot2) = CreateCoil(limb_distance/2) + coil2.mat("coil_2") + + oil = OrthoBrick((-domain_size/2, -domain_size_y/2, -domain_size/2), (domain_size/2, domain_size_y/2, domain_size/2)).bc("tank") - core # - coil1 - coil2 + + geo.Add(core.mat("core"), col=(0.4,0.4,0.4)) + geo.Add(coil1, col=(0.72, 0.45, 0.2)) + geo.Add(coil2, col=(0.72, 0.45, 0.2)) + geo.Add(oil.mat("oil"), transparent=True) + mesh = geo.GenerateMesh() + mesh.BoundaryLayer("core_front", [0.001, 0.002], "core", "core", outside=outside) + ngs = pytest.importorskip("ngsolve") + mesh = ngs.Mesh(mesh) + capture = capfd.readouterr() + assert not "elements are not matching" in capture.out + assert ngs.Integrate(1, mesh.Materials("core")) == pytest.approx(0.0212 if outside else 0.02) + assert ngs.Integrate(1, mesh.Materials("oil")) == pytest.approx(0.9868 if outside else 0.988) From 85e8c09ff6626b12480f4919a26a7086d4c20579 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Br=C3=BCns?= Date: Wed, 3 Mar 2021 17:03:29 +0100 Subject: [PATCH 350/384] Fix GetTimeCounter for Aarch64 variants Neither GCC nor Clang define an __arm64__ preprocessor macro, but use __aarch64__ (MSVC uses _MARM_64). Add a "64" suffix to the define, i.e. NETGEN_ARCH_ARM64 to make it more obvious in only refers to aarch64, and to be in line with NETGEN_ARCH_AMD64. Replace the (Clang specific) __builtin_readcyclecounter with inline asm: - The function return cycles (i.e. varies with CPU frequency), not time - It may return 0, depending on the PMU settings - It may cause an illegal instruction, in case it is not trapped by the kernel, e.g. on FreeBSD. Reading the generic timer/counter CNTVCT_EL0 instead of PMCCNTR_EL0 avoids these pitfalls. The inline asm works on GCC and Clang, instead of Clang only for the builtin. --- libsrc/core/ngcore_api.hpp | 6 +++++- libsrc/core/simd.hpp | 2 +- libsrc/core/utils.hpp | 11 +++++++---- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/libsrc/core/ngcore_api.hpp b/libsrc/core/ngcore_api.hpp index 330e7e33..9c977c1c 100644 --- a/libsrc/core/ngcore_api.hpp +++ b/libsrc/core/ngcore_api.hpp @@ -71,7 +71,11 @@ #define NETGEN_ARCH_AMD64 #endif -#if defined(__arm64__) || defined(_M_ARM64) +#if defined(__aarch64__) || defined(_M_ARM64) +#define NETGEN_ARCH_ARM64 +#endif + +#if defined(__arm__) || defined(_M_ARM) #define NETGEN_ARCH_ARM #endif diff --git a/libsrc/core/simd.hpp b/libsrc/core/simd.hpp index e809d6fe..3459e66d 100644 --- a/libsrc/core/simd.hpp +++ b/libsrc/core/simd.hpp @@ -26,7 +26,7 @@ #include "simd_avx512.hpp" #endif -#ifdef __arm64__ +#ifdef __aarch64__ #include "simd_arm64.hpp" #endif diff --git a/libsrc/core/utils.hpp b/libsrc/core/utils.hpp index ca015ae3..102ff319 100644 --- a/libsrc/core/utils.hpp +++ b/libsrc/core/utils.hpp @@ -10,7 +10,7 @@ #include "ngcore_api.hpp" // for NGCORE_API and CPU arch macros -#if defined(__APPLE__) && defined(NETGEN_ARCH_ARM) +#if defined(__APPLE__) && defined(NETGEN_ARCH_ARM64) #include #endif @@ -58,12 +58,15 @@ namespace ngcore inline TTimePoint GetTimeCounter() noexcept { -#if defined(__APPLE__) && defined(NETGEN_ARCH_ARM) +#if defined(__APPLE__) && defined(NETGEN_ARCH_ARM64) return mach_absolute_time(); #elif defined(NETGEN_ARCH_AMD64) return __rdtsc(); -#elif defined(NETGEN_ARCH_ARM) - return __builtin_readcyclecounter(); +#elif defined(NETGEN_ARCH_ARM64) && defined(__GNUC__) + // __GNUC__ is also defined by CLANG. Use inline asm to read Generic Timer + unsigned long long tics; + __asm __volatile("mrs %0, CNTVCT_EL0" : "=&r" (tics)); + return tics; #else #warning "Unsupported CPU architecture" return 0; From 883baf4189ad2ac4ac5e8643332606324fc46590 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Br=C3=BCns?= Date: Mon, 8 Mar 2021 02:33:00 +0100 Subject: [PATCH 351/384] Remove occconstruction.cpp from list of library sources Since commit 0c3c3f32d173b3f7edcb40f9f6447fae60f02c05 ("occ build visualization mesh") occgeometry.cpp does not contain any compiled code, and it has not been used at least for 12 years. As the file includes quite some header files removing it from the sources should save some compile time. --- libsrc/occ/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsrc/occ/CMakeLists.txt b/libsrc/occ/CMakeLists.txt index 9db6271b..ea5a756e 100644 --- a/libsrc/occ/CMakeLists.txt +++ b/libsrc/occ/CMakeLists.txt @@ -2,7 +2,7 @@ add_definitions(-DNGINTERFACE_EXPORTS) add_library(occ ${NG_LIB_TYPE} Partition_Inter2d.cxx Partition_Inter3d.cxx Partition_Loop.cxx Partition_Loop2d.cxx Partition_Loop3d.cxx Partition_Spliter.cxx - occconstruction.cpp occgenmesh.cpp occgeom.cpp occmeshsurf.cpp python_occ.cpp + occgenmesh.cpp occgeom.cpp occmeshsurf.cpp python_occ.cpp ) if(USE_GUI) add_library(occvis ${NG_LIB_TYPE} vsocc.cpp) From 2767672286fa6ece29417eab4f399deb3ec62b3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Br=C3=BCns?= Date: Wed, 10 Mar 2021 00:45:56 +0100 Subject: [PATCH 352/384] Cleanup use of M_PI/PI defines gprim/geom2d.cpp includes mystdlib.h, which already has a fallback define for M_PI. As geomfuncs.cpp also includes mystdlib.h, use M_PI instead of a truncated value. occ/Partition_Loop2d.cxx already gets M_PI from the opencascade headers (~everything includes Standard_Real.hxx, which includes Standard_math.hxx, which sets _USE_MATH_DEFINES for Windows and includes math.h). --- libsrc/gprim/geom2d.cpp | 4 ---- libsrc/gprim/geomfuncs.cpp | 2 +- libsrc/occ/Partition_Loop2d.cxx | 2 -- 3 files changed, 1 insertion(+), 7 deletions(-) diff --git a/libsrc/gprim/geom2d.cpp b/libsrc/gprim/geom2d.cpp index 7d051359..f50131aa 100644 --- a/libsrc/gprim/geom2d.cpp +++ b/libsrc/gprim/geom2d.cpp @@ -3,10 +3,6 @@ #include #include -#ifndef M_PI -#define M_PI 3.14159265358979323846 -#endif - namespace netgen { diff --git a/libsrc/gprim/geomfuncs.cpp b/libsrc/gprim/geomfuncs.cpp index b2ac8382..6608c072 100644 --- a/libsrc/gprim/geomfuncs.cpp +++ b/libsrc/gprim/geomfuncs.cpp @@ -83,7 +83,7 @@ double Det (const Mat<3,3> & m) void EigenValues (const Mat<3,3> & m, Vec<3> & ev) { - const double pi = 3.141592; + const double pi = M_PI; double a, b, c, d; double p, q; double arg; diff --git a/libsrc/occ/Partition_Loop2d.cxx b/libsrc/occ/Partition_Loop2d.cxx index 22740a58..1c3d7957 100644 --- a/libsrc/occ/Partition_Loop2d.cxx +++ b/libsrc/occ/Partition_Loop2d.cxx @@ -52,8 +52,6 @@ #include #include -#define PI 3.14159265358979323846 - //======================================================================= //function : Partition_Loop2d //purpose : From 8abd52a47b6da9d53f25a8171091124ba8cb7d5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Br=C3=BCns?= Date: Wed, 10 Mar 2021 01:06:11 +0100 Subject: [PATCH 353/384] Remove two unused variables --- libsrc/occ/occgenmesh.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/libsrc/occ/occgenmesh.cpp b/libsrc/occ/occgenmesh.cpp index 314d405a..783ba96b 100644 --- a/libsrc/occ/occgenmesh.cpp +++ b/libsrc/occ/occgenmesh.cpp @@ -244,9 +244,6 @@ namespace netgen hvalue[0] = 0; pnt = c->Value(s0); - double olddist = 0; - double dist = 0; - int tmpVal = (int)(DIVIDEEDGESECTIONS); for (int i = 1; i <= tmpVal; i++) @@ -259,9 +256,6 @@ namespace netgen //(*testout) << "mesh.GetH(Point3d(pnt.X(), pnt.Y(), pnt.Z())) " << mesh.GetH(Point3d(pnt.X(), pnt.Y(), pnt.Z())) // << " pnt.Distance(oldpnt) " << pnt.Distance(oldpnt) << endl; - - olddist = dist; - dist = pnt.Distance(oldpnt); } // nsubedges = int(ceil(hvalue[DIVIDEEDGESECTIONS])); From 3c13e416922073fb91436c4ad7d74467a8e46e6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Br=C3=BCns?= Date: Thu, 11 Mar 2021 23:25:49 +0100 Subject: [PATCH 354/384] Remove duplicated includes from occgeom.hpp Each of the duplicated header files have an include guard, so including it twice is just a small waste of processing time. --- libsrc/occ/occgeom.hpp | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/libsrc/occ/occgeom.hpp b/libsrc/occ/occgeom.hpp index a491952f..6f70541e 100644 --- a/libsrc/occ/occgeom.hpp +++ b/libsrc/occ/occgeom.hpp @@ -31,38 +31,16 @@ #include "Poly_Triangle.hxx" #include "GProp_GProps.hxx" #include "BRepGProp.hxx" -#include "Geom_Surface.hxx" -#include "TopExp.hxx" #include "gp_Pnt.hxx" #include "TopoDS.hxx" #include "TopoDS_Solid.hxx" #include "TopExp_Explorer.hxx" #include "TopTools_ListIteratorOfListOfShape.hxx" -#include "BRep_Tool.hxx" -#include "Geom_Curve.hxx" -#include "Geom2d_Curve.hxx" -#include "Geom_Surface.hxx" -#include "GeomAPI_ProjectPointOnSurf.hxx" -#include "GeomAPI_ProjectPointOnCurve.hxx" #include "TopoDS_Wire.hxx" #include "BRepTools_WireExplorer.hxx" -#include "BRepTools.hxx" #include "TopTools_IndexedMapOfShape.hxx" -#include "TopExp.hxx" -#include "BRepBuilderAPI_MakeVertex.hxx" -#include "BRepBuilderAPI_MakeShell.hxx" -#include "BRepBuilderAPI_MakeSolid.hxx" -#include "BRepOffsetAPI_Sewing.hxx" #include "BRepLProp_CLProps.hxx" -#include "BRepLProp_SLProps.hxx" -#include "BRepAdaptor_Surface.hxx" #include "BRepAdaptor_Curve.hxx" -#include "Poly_Triangulation.hxx" -#include "Poly_Array1OfTriangle.hxx" -#include "TColgp_Array1OfPnt2d.hxx" -#include "Poly_Triangle.hxx" -#include "GProp_GProps.hxx" -#include "BRepGProp.hxx" #include "TopoDS_Shape.hxx" #include "TopoDS_Face.hxx" #include "IGESToBRep_Reader.hxx" From cf4d9eff33486817f001a361f5346b1d11728672 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Br=C3=BCns?= Date: Wed, 10 Mar 2021 01:57:16 +0100 Subject: [PATCH 355/384] Modernize code, replace Handle_ with Handle(X) Same like c35297a8fb158be47772cb5fc9cee76ca88ff871 --- libsrc/occ/occgeom.cpp | 36 ++++++++++++++++++------------------ libsrc/occ/occgeom.hpp | 2 +- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/libsrc/occ/occgeom.cpp b/libsrc/occ/occgeom.cpp index a3e8ddd3..cc5b9f65 100644 --- a/libsrc/occ/occgeom.cpp +++ b/libsrc/occ/occgeom.cpp @@ -282,7 +282,7 @@ namespace netgen double surfacecont = 0; { - Handle_ShapeBuild_ReShape rebuild = new ShapeBuild_ReShape; + Handle(ShapeBuild_ReShape) rebuild = new ShapeBuild_ReShape; rebuild->Apply(shape); for (exp1.Init (shape, TopAbs_EDGE); exp1.More(); exp1.Next()) { @@ -313,7 +313,7 @@ namespace netgen cout << endl << "- repairing faces" << endl; Handle(ShapeFix_Face) sff; - Handle_ShapeBuild_ReShape rebuild = new ShapeBuild_ReShape; + Handle(ShapeBuild_ReShape) rebuild = new ShapeBuild_ReShape; rebuild->Apply(shape); @@ -370,7 +370,7 @@ namespace netgen { - Handle_ShapeBuild_ReShape rebuild = new ShapeBuild_ReShape; + Handle(ShapeBuild_ReShape) rebuild = new ShapeBuild_ReShape; rebuild->Apply(shape); for (exp1.Init (shape, TopAbs_EDGE); exp1.More(); exp1.Next()) { @@ -387,7 +387,7 @@ namespace netgen cout << endl << "- fixing small edges" << endl; Handle(ShapeFix_Wire) sfw; - Handle_ShapeBuild_ReShape rebuild = new ShapeBuild_ReShape; + Handle(ShapeBuild_ReShape) rebuild = new ShapeBuild_ReShape; rebuild->Apply(shape); @@ -454,7 +454,7 @@ namespace netgen { BuildFMap(); - Handle_ShapeBuild_ReShape rebuild = new ShapeBuild_ReShape; + Handle(ShapeBuild_ReShape) rebuild = new ShapeBuild_ReShape; rebuild->Apply(shape); for (exp1.Init (shape, TopAbs_EDGE); exp1.More(); exp1.Next()) @@ -482,7 +482,7 @@ namespace netgen { - Handle_ShapeBuild_ReShape rebuild = new ShapeBuild_ReShape; + Handle(ShapeBuild_ReShape) rebuild = new ShapeBuild_ReShape; rebuild->Apply(shape); for (exp1.Init (shape, TopAbs_EDGE); exp1.More(); exp1.Next()) { @@ -608,7 +608,7 @@ namespace netgen { - Handle_ShapeBuild_ReShape rebuild = new ShapeBuild_ReShape; + Handle(ShapeBuild_ReShape) rebuild = new ShapeBuild_ReShape; rebuild->Apply(shape); for (exp1.Init (shape, TopAbs_EDGE); exp1.More(); exp1.Next()) { @@ -653,7 +653,7 @@ namespace netgen TopoDS_Solid solid = TopoDS::Solid(exp0.Current()); TopoDS_Solid newsolid = solid; BRepLib::OrientClosedSolid (newsolid); - Handle_ShapeBuild_ReShape rebuild = new ShapeBuild_ReShape; + Handle(ShapeBuild_ReShape) rebuild = new ShapeBuild_ReShape; // rebuild->Apply(shape); rebuild->Replace(solid, newsolid); TopoDS_Shape newshape = rebuild->Apply(shape, TopAbs_COMPSOLID);//, 1); @@ -1076,7 +1076,7 @@ namespace netgen TopoDS_Solid solid = TopoDS::Solid(exp0.Current()); TopoDS_Solid newsolid = solid; BRepLib::OrientClosedSolid (newsolid); - Handle_ShapeBuild_ReShape rebuild = new ShapeBuild_ReShape; + Handle(ShapeBuild_ReShape) rebuild = new ShapeBuild_ReShape; rebuild->Replace(solid, newsolid); TopoDS_Shape newshape = rebuild->Apply(shape, TopAbs_SHAPE, 1); @@ -1408,10 +1408,10 @@ namespace netgen static Timer timer_getnames("LoadOCC-get names"); // Initiate a dummy XCAF Application to handle the STEP XCAF Document - static Handle_XCAFApp_Application dummy_app = XCAFApp_Application::GetApplication(); + static Handle(XCAFApp_Application) dummy_app = XCAFApp_Application::GetApplication(); // Create an XCAF Document to contain the STEP file itself - Handle_TDocStd_Document step_doc; + Handle(TDocStd_Document) step_doc; // Check if a STEP File is already open under this handle, if so, close it to prevent // Segmentation Faults when trying to create a new document @@ -1441,8 +1441,8 @@ namespace netgen timer_transfer.Stop(); // Read in the shape(s) and the colours present in the STEP File - Handle_XCAFDoc_ShapeTool step_shape_contents = XCAFDoc_DocumentTool::ShapeTool(step_doc->Main()); - Handle_XCAFDoc_ColorTool step_colour_contents = XCAFDoc_DocumentTool::ColorTool(step_doc->Main()); + Handle(XCAFDoc_ShapeTool) step_shape_contents = XCAFDoc_DocumentTool::ShapeTool(step_doc->Main()); + Handle(XCAFDoc_ColorTool) step_colour_contents = XCAFDoc_DocumentTool::ColorTool(step_doc->Main()); TDF_LabelSequence step_shapes; step_shape_contents->GetShapes(step_shapes); @@ -1567,10 +1567,10 @@ namespace netgen OCCGeometry *occgeo; occgeo = new OCCGeometry; // Initiate a dummy XCAF Application to handle the IGES XCAF Document - static Handle_XCAFApp_Application dummy_app = XCAFApp_Application::GetApplication(); + static Handle(XCAFApp_Application) dummy_app = XCAFApp_Application::GetApplication(); // Create an XCAF Document to contain the IGES file itself - Handle_TDocStd_Document iges_doc; + Handle(TDocStd_Document) iges_doc; // Check if a IGES File is already open under this handle, if so, close it to prevent // Segmentation Faults when trying to create a new document @@ -1596,8 +1596,8 @@ namespace netgen reader.Transfer(iges_doc); // Read in the shape(s) and the colours present in the IGES File - Handle_XCAFDoc_ShapeTool iges_shape_contents = XCAFDoc_DocumentTool::ShapeTool(iges_doc->Main()); - Handle_XCAFDoc_ColorTool iges_colour_contents = XCAFDoc_DocumentTool::ColorTool(iges_doc->Main()); + Handle(XCAFDoc_ShapeTool) iges_shape_contents = XCAFDoc_DocumentTool::ShapeTool(iges_doc->Main()); + Handle(XCAFDoc_ColorTool) iges_colour_contents = XCAFDoc_DocumentTool::ColorTool(iges_doc->Main()); TDF_LabelSequence iges_shapes; iges_shape_contents->GetShapes(iges_shapes); @@ -1667,7 +1667,7 @@ namespace netgen // Fixed a bug in the OpenCascade XDE Colour handling when // opening BREP Files, since BREP Files have no colour data. // Hence, the face_colours Handle needs to be created as a NULL handle. - occgeo->face_colours = Handle_XCAFDoc_ColorTool(); + occgeo->face_colours = Handle(XCAFDoc_ColorTool)(); occgeo->face_colours.Nullify(); occgeo->changed = 1; occgeo->BuildFMap(); diff --git a/libsrc/occ/occgeom.hpp b/libsrc/occ/occgeom.hpp index a491952f..95853e94 100644 --- a/libsrc/occ/occgeom.hpp +++ b/libsrc/occ/occgeom.hpp @@ -221,7 +221,7 @@ namespace netgen // OpenCascade XDE Support // XCAF Handle to make the face colours available to the rest of // the system - Handle_XCAFDoc_ColorTool face_colours; + Handle(XCAFDoc_ColorTool) face_colours; mutable int changed; mutable NgArray facemeshstatus; From c77da3246382c0b169cdc93712ddb80156ce0e42 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Tue, 16 Mar 2021 18:09:07 +0100 Subject: [PATCH 356/384] skip fixed points when checking for mixed mesh --- libsrc/meshing/improve2.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/libsrc/meshing/improve2.cpp b/libsrc/meshing/improve2.cpp index fe40259f..acbfa1ea 100644 --- a/libsrc/meshing/improve2.cpp +++ b/libsrc/meshing/improve2.cpp @@ -190,7 +190,12 @@ namespace netgen SurfaceElementIndex sei(i); seia[i] = sei; if (mesh[sei].GetNP() != 3) - mixed = true; + { + const auto & sel = mesh[sei]; + for(auto i : Range(sel.GetNP())) + if(mesh[sel[i]].Type() == INNERPOINT) + mixed = true; + } }); } else From 98770dbf9498c61fd575cf8bcba5a469ea7b51c1 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Tue, 16 Mar 2021 18:20:40 +0100 Subject: [PATCH 357/384] 2d boundary layers --- libsrc/meshing/boundarylayer.cpp | 585 +++++++++++++++++++++++++++++++ libsrc/meshing/boundarylayer.hpp | 1 + 2 files changed, 586 insertions(+) diff --git a/libsrc/meshing/boundarylayer.cpp b/libsrc/meshing/boundarylayer.cpp index 4539887c..315a062e 100644 --- a/libsrc/meshing/boundarylayer.cpp +++ b/libsrc/meshing/boundarylayer.cpp @@ -1,5 +1,8 @@ #include #include "meshing.hpp" +#include "meshing2.hpp" +#include "global.hpp" +#include "../geom2d/csg2d.hpp" namespace netgen { @@ -625,4 +628,586 @@ namespace netgen mesh.GetFaceDescriptor(i).SetDomainIn(new_mat_nr); } } + + void AddDirection( Vec<3> & a, Vec<3> b ) + { + if(a.Length2()==0.) + { + a = b; + return; + } + + if(b.Length2()==0.) + return; + + auto ab = a * b; + if(fabs(ab)>1-1e-8) + return; + + Mat<2> m; + m(0,0) = a[0]; + m(0,1) = a[1]; + m(1,0) = b[0]; + m(1,1) = b[1]; + Vec<2> lam; + Vec<2> rhs; + rhs[0] = a[0]-b[0]; + rhs[1] = a[1]-b[1]; + + const auto Dot = [](Vec<3> a, Vec<3> b) + { return a[0]*b[0] + a[1]*b[1] + a[2]*b[2]; }; + + rhs[0] = Dot(a,a); + rhs[1] = Dot(b,b); + + m.Solve(rhs, lam); + a[0] = lam[0]; + a[1] = lam[1]; + a[2] = 0.0; + return; + } + + static void Generate2dMesh( Mesh & mesh, int domain ) + { + Box<3> box{Box<3>::EMPTY_BOX}; + for(const auto & seg : mesh.LineSegments()) + if (seg.si == domain) + for (auto pi : {seg[0], seg[1]}) + box.Add(mesh[pi]); + + MeshingParameters mp; + Meshing2 meshing (*mesh.GetGeometry(), mp, box); + + Array compress(mesh.GetNP()); + compress = PointIndex::INVALID; + + PointIndex cnt = PointIndex::BASE; + for(const auto & seg : mesh.LineSegments()) + if (seg.si == domain) + for (auto pi : {seg[0], seg[1]}) + if (compress[pi]==PointIndex{PointIndex::INVALID}) + { + meshing.AddPoint(mesh[pi], pi); + compress[pi] = cnt++; + } + + PointGeomInfo gi; + gi.trignum = domain; + for(const auto & seg : mesh.LineSegments()) + if (seg.si == domain) + meshing.AddBoundaryElement (compress[seg[0]], compress[seg[1]], gi, gi); + + auto oldnf = mesh.GetNSE(); + auto res = meshing.GenerateMesh (mesh, mp, mp.maxh, domain); + for (SurfaceElementIndex sei : Range(oldnf, mesh.GetNSE())) + mesh[sei].SetIndex (domain); + + int hsteps = mp.optsteps2d; + + const char * optstr = mp.optimize2d.c_str(); + MeshOptimize2d meshopt(mesh); + meshopt.SetFaceIndex(domain); + meshopt.SetMetricWeight (mp.elsizeweight); + for (size_t j = 1; j <= strlen(optstr); j++) + { + switch (optstr[j-1]) + { + case 's': + { // topological swap + meshopt.EdgeSwapping (0); + break; + } + case 'S': + { // metric swap + meshopt.EdgeSwapping (1); + break; + } + case 'm': + { + meshopt.ImproveMesh(mp); + break; + } + case 'c': + { + meshopt.CombineImprove(); + break; + } + default: + cerr << "Optimization code " << optstr[j-1] << " not defined" << endl; + } + } + + mesh.Compress(); + mesh.OrderElements(); + mesh.SetNextMajorTimeStamp(); + + } + + void GenerateBoundaryLayer2 (Mesh & mesh, int domain, const Array & boundaries, const Array & thicknesses) + { + int np = mesh.GetNP(); + int nseg = mesh.GetNSeg(); + int ne = mesh.GetNSE(); + mesh.UpdateTopology(); + + double total_thickness = 0.0; + for(auto thickness : thicknesses) + total_thickness += thickness; + + Array, PointIndex> mapto(np); + + // Bit array to keep track of segments already processed + BitArray segs_done(nseg); + segs_done.Clear(); + + // map for all segments with same points + // points to pair of SegmentIndex, int + // int is type of other segment, either: + // TODO: recognize "end points" of boundary layer and implement closure properly + Array>, SegmentIndex> segmap(mesh.GetNSeg()); + + // moved segments + Array moved_segs; + + Array, PointIndex> growthvectors(np); + growthvectors = 0.; + + auto & meshtopo = mesh.GetTopology(); + + Array seg2surfel(mesh.GetNSeg()); + seg2surfel = -1; + NgArray temp_els; + for(auto si : Range(mesh.LineSegments())) + { + meshtopo.GetSegmentSurfaceElements ( si+1, temp_els ); + // NgArray surfeledges; + // meshtopo.GetSurfaceElementEdges(si+1, surfeledges); + for(auto seli : temp_els) + if(mesh[seli].GetIndex() == mesh[si].si) + seg2surfel[si] = seli; + } + + Array segments; + + // surface index map + Array si_map(mesh.GetNFD()+1); + si_map = -1; + + int fd_old = mesh.GetNFD(); + + int max_edge_nr = -1; + int max_domain = -1; + + for(const auto& seg : mesh.LineSegments()) + { + if(seg.epgeominfo[0].edgenr > max_edge_nr) + max_edge_nr = seg.epgeominfo[0].edgenr; + if(seg.si > max_domain) + max_domain = seg.si; + } + + BitArray active_boundaries(max_edge_nr+1); + BitArray active_segments(nseg); + active_boundaries.Clear(); + active_segments.Clear(); + + if(boundaries.Size() == 0) + active_boundaries.Set(); + else + for(auto edgenr : boundaries) + active_boundaries.SetBit(edgenr); + + for(auto segi : Range(mesh.LineSegments())) + { + const auto seg = mesh[segi]; + if(active_boundaries.Test(seg.epgeominfo[0].edgenr) && seg.si==domain) + active_segments.SetBit(segi); + } + + for(auto segi : Range(mesh.LineSegments())) + { + const auto& seg = mesh[segi]; + auto si = seg.si; + + if(si_map[si]!=-1) + continue; + + if(!active_segments.Test(segi)) + continue; + + int new_si = mesh.GetNFD()+1; + FaceDescriptor new_fd(-1, 0, 0, -1); + new_fd.SetBCProperty(new_si); + mesh.AddFaceDescriptor(new_fd); + si_map[si] = new_si; + mesh.SetBCName(new_si-1, "mapped_" + mesh.GetBCName(si-1)); + } + + for(auto si : Range(mesh.LineSegments())) + { + if(segs_done[si]) continue; + segs_done.SetBit(si); + const auto& segi = mesh[si]; + if(si_map[segi.si] == -1) continue; + if(!active_boundaries.Test(segi.epgeominfo[0].edgenr)) + continue; + segmap[si].Append(make_pair(si, 0)); + moved_segs.Append(si); + for(auto sj : Range(mesh.LineSegments())) + { + if(segs_done.Test(sj)) continue; + const auto& segj = mesh[sj]; + if((segi[0] == segj[0] && segi[1] == segj[1]) || + (segi[0] == segj[1] && segi[1] == segj[0])) + { + segs_done.SetBit(sj); + int type = 0; + segmap[si].Append(make_pair(sj, type)); + } + } + } + + // calculate growth vectors (average normal vectors of adjacent segments at each point) + for (auto si : moved_segs) + { + auto & seg = mesh[si]; + + meshtopo.GetSegmentSurfaceElements ( si+1, temp_els ); + ArrayMem seg_domains; + + temp_els.SetSize(0); + if(seg2surfel[si]!=-1) + temp_els.Append(seg2surfel[si]); + + int n_temp_els = temp_els.Size(); + if(n_temp_els==0) + continue; + + int dom0 = mesh[temp_els[0]].GetIndex(); + int dom1 = n_temp_els==2 ? mesh[temp_els[1]].GetIndex() : 0; + + bool in_dom0 = dom0 == domain; + bool in_dom1 = dom1 == domain; + + if(!in_dom0 && !in_dom1) + continue; + + int side = in_dom0 ? 0 : 1; + + auto & sel = mesh[ temp_els[side] ]; + + int domain = sel.GetIndex(); + Vec<3> pcenter = 0.0; + for(auto i : IntRange(sel.GetNP())) + { + for(auto d : IntRange(3)) + pcenter[d] += mesh[sel[i]][d]; + } + pcenter = 1.0/sel.GetNP() * pcenter; + + auto n = mesh[seg[1]] - mesh[seg[0]]; + n = {-n[1], n[0], 0}; + n.Normalize(); + + Vec<3> p0{mesh[seg[0]]}; + Vec<3> p1{mesh[seg[0]]}; + + + auto v = pcenter -0.5*(p0+p1); + + const auto Dot = [](Vec<3> a, Vec<3> b) + { return a[0]*b[0] + a[1]*b[1] + a[2]*b[2]; }; + if(Dot(n, v)<0) + n = -1*n; + + AddDirection(growthvectors[seg[0]], n); + AddDirection(growthvectors[seg[1]], n); + } + + // reduce growthvectors where necessary to avoid overlaps/slim regions + const auto getSegmentBox = [&] (SegmentIndex segi) + { + PointIndex pi0=mesh[segi][0], pi1=mesh[segi][1]; + Box<3> box( mesh[pi0], mesh[pi1] ); + box.Add( mesh[pi0]+growthvectors[pi0] ); + box.Add( mesh[pi1]+growthvectors[pi1] ); + return box; + }; + + Array growth(np); + growth = 1.0; + + const auto Dot = [](auto a, auto b) + { return a[0]*b[0] + a[1]*b[1] + a[2]*b[2]; }; + + const auto restrictGrowthVectors = [&] (SegmentIndex segi0, SegmentIndex segi1) + { + if(!active_segments.Test(segi0)) + return; + + const auto & seg0 = mesh[segi0]; + const auto & seg1 = mesh[segi1]; + + if(seg0.si != seg1.si) + return; + + if(segi0 == segi1) + return; + + if(seg0[0]==seg1[0] || seg0[0]==seg1[1] || seg0[1]==seg1[0] || seg0[1] == seg1[1]) + return; + + auto n = mesh[seg0[0]] - mesh[seg0[1]]; + n = {-n[1], n[0], 0}; + n.Normalize(); + if(Dot(n, growthvectors[seg0[0]])<0) n = -n; + if(Dot(n, growthvectors[seg0[1]])<0) n = -n; + + auto n1 = mesh[seg1[0]] - mesh[seg1[1]]; + n1 = {-n1[1], n1[0], 0}; + n1.Normalize(); + if(Dot(n1, growthvectors[seg1[0]])<0) n1 = -n; + if(Dot(n1, growthvectors[seg1[1]])<0) n1 = -n; + + // check if angle between normal vectors is less than 180 degrees (cant overlap for opposing directions) +// if(n[0]*n1[1]-n[1]*n1[0]<0.0) +// return; + + auto p10 = mesh[seg1[0]]; + auto p11 = mesh[seg1[1]]; + + for ( auto pi : {seg0[0], seg0[1]} ) + { + if(growthvectors[pi] == 0.0) + continue; + + PointIndex pi1 = seg0[0] + seg0[1] - pi; + auto p1 = mesh[pi1]; + auto p = mesh[pi]; + + Point<3> points[] = { p10, p11, p10+total_thickness*growthvectors[seg1[0]], p11+total_thickness*growthvectors[seg1[1]], p1+total_thickness*growthvectors[pi1] }; + + Vec<3> gn{ growthvectors[pi][1], -growthvectors[pi][0], 0.0 }; + if(Dot(gn, p1-p) < 0) + gn = -gn; + + double d0 = Dot(gn, p); + double d1 = Dot(gn, p1); + if(d0>d1) + Swap(d0,d1); + + bool all_left=true, all_right=true; + + for (auto i: Range(4)) + { + auto p_other = points[i]; + auto dot = Dot(gn,p_other); + if(dot>d0) all_left = false; + if(dot points[] = { p10, p10+t*growthvectors[seg1[0]], p11, p11+t*growthvectors[seg1[1]] }; + auto p0 = mesh[pi]; + auto p1 = p0 + t*growthvectors[pi]; + auto P2 = [](Point<3> p) { return Point<2>{p[0], p[1]}; }; + ArrayMem, 4> intersections; + + double alpha, beta; + + if(X_INTERSECTION == intersect( P2(p0), P2(p1), P2(points[0]), P2(points[2]), alpha, beta )) + intersections.Append({alpha, 0.0}); + + if(X_INTERSECTION == intersect( P2(p0), P2(p1), P2(points[1]), P2(points[3]), alpha, beta )) + intersections.Append({alpha, 1.0}); + + if(X_INTERSECTION == intersect( P2(p0), P2(p1), P2(points[0]), P2(points[1]), alpha, beta )) + intersections.Append({alpha, beta}); + + if(X_INTERSECTION == intersect( P2(p0), P2(p1), P2(points[2]), P2(points[3]), alpha, beta )) + intersections.Append({alpha, beta}); + + QuickSort(intersections); + for(auto [alpha,beta] : intersections) + { + if(!active_segments.Test(segi1)) + growth[pi] = min(growth[pi], alpha); + else + { + double mean = 0.5*(alpha+beta); + growth[pi] = min(growth[pi], mean); + growth[seg1[0]] = min(growth[seg1[0]], mean); + growth[seg1[1]] = min(growth[seg1[1]], mean); + } + } + } + } + }; + + Box<3> box(Box<3>::EMPTY_BOX); + for (auto segi : Range(mesh.LineSegments())) + { + auto segbox = getSegmentBox( segi ); + box.Add(segbox.PMin()); + box.Add(segbox.PMax()); + } + BoxTree<3> segtree(box); + + for (auto segi : Range(mesh.LineSegments())) + { + auto p2 = [](Point<3> p) { return Point<2>{p[0], p[1]}; }; + + auto seg = mesh[segi]; + double alpha,beta; + intersect( p2(mesh[seg[0]]), p2(mesh[seg[0]]+total_thickness*growthvectors[seg[0]]), p2(mesh[seg[1]]), p2(mesh[seg[1]]+total_thickness*growthvectors[seg[1]]), alpha, beta ); + + if(beta>0 && alpha>0 && alpha<1.1) + growth[seg[0]] = min(growth[seg[0]], 0.8*alpha); + if(alpha>0 && beta>0 && beta<1.1) + growth[seg[1]] = min(growth[seg[1]], 0.8*beta); + + for (auto segj : Range(mesh.LineSegments())) + if(segi!=segj) + restrictGrowthVectors(segi, segj); + } + + for( auto pi : Range(growthvectors)) + growthvectors[pi] *= growth[pi]; + + + // insert new points + for(PointIndex pi : Range(mesh.Points())) + if(growthvectors[pi].Length2()!=0) + { + + auto & pnew = mapto[pi]; + auto dist = 0.0; + for(auto t : thicknesses) + { + dist+=t; + pnew.Append( mesh.AddPoint( mesh[pi] + dist*growthvectors[pi] ) ); + mesh[pnew.Last()].SetType(FIXEDPOINT); + } + } + + map, int> seg2edge; + + // insert new elements ( and move old ones ) + for(auto si : moved_segs) + { + auto seg = mesh[si]; + + bool swap = false; + auto & pm0 = mapto[seg[0]]; + auto & pm1 = mapto[seg[1]]; + + auto newindex = si_map[seg.si]; + + { + Segment s = seg; + s[0] = pm0.Last(); + s[1] = pm1.Last(); + s[2] = PointIndex::INVALID; + auto pair = s[0] < s[1] ? make_pair(s[0], s[1]) : make_pair(s[1], s[0]); + if(seg2edge.find(pair) == seg2edge.end()) + seg2edge[pair] = ++max_edge_nr; + s.edgenr = seg2edge[pair]; + s.si = seg.si; + mesh.AddSegment(s); + + Swap(s[0], s[1]); + s.si = newindex; + mesh.AddSegment(s); + } + + for ( auto i : Range(thicknesses)) + { + PointIndex pi0, pi1, pi2, pi3; + + if(i==0) + { + pi0 = seg[0]; + pi1 = seg[1]; + } + else + { + pi0 = pm0[i-1]; + pi1 = pm1[i-1]; + } + + pi2 = pm1[i]; + pi3 = pm0[i]; + + if(i==0) + { + auto p0 = mesh[pi0]; + auto p1 = mesh[pi1]; + auto q0 = mesh[pi2]; + auto q1 = mesh[pi3]; + + Vec<2> n = {-p1[1]+p0[1], p1[0]-p0[0]}; + Vec<2> v = { q0[0]-p0[0], q0[1]-p0[1]}; + if(n[0]*v[0]+n[1]*v[1]<0) + swap = true; + } + + Element2d newel; + newel.SetType(QUAD); + newel[0] = pi0; + newel[1] = pi1; + newel[2] = pi2; + newel[3] = pi3; + newel.SetIndex(si_map[seg.si]); + +// if(swap) +// { +// Swap(newel[0], newel[1]); +// Swap(newel[2], newel[3]); +// } + + mesh.AddSurfaceElement(newel); + + } + // segment now adjacent to new 2d-domain! + mesh[si].si = si_map[seg.si]; + } + + for(auto pi : Range(mapto)) + { + if(mapto[pi].Size() == 0) + continue; + auto pnew = mapto[pi].Last(); + NgArray old_els; + meshtopo.GetVertexSurfaceElements( pi, old_els); + for(auto old_sei : old_els) + { + if(mesh[old_sei].GetIndex() == domain) + { + auto & old_el = mesh[old_sei]; + for(auto i : IntRange(old_el.GetNP())) + if(old_el[i]==pi) + old_el[i] = pnew; + } + } + } + + for(auto & sel : mesh.SurfaceElements()) + if(sel.GetIndex() == domain) + sel.Delete(); + + mesh.Compress(); + mesh.CalcSurfacesOfNode(); + + Generate2dMesh(mesh, domain); + } + } diff --git a/libsrc/meshing/boundarylayer.hpp b/libsrc/meshing/boundarylayer.hpp index 1d33fab1..9e78a13d 100644 --- a/libsrc/meshing/boundarylayer.hpp +++ b/libsrc/meshing/boundarylayer.hpp @@ -24,5 +24,6 @@ public: DLL_HEADER void GenerateBoundaryLayer (Mesh & mesh, const BoundaryLayerParameters & blp); +DLL_HEADER void GenerateBoundaryLayer2 (Mesh & mesh, int domain, const Array & boundaries, const Array & thicknesses); #endif From 69bc02a74da6ce90c475437e4e3f95d39417523f Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Wed, 17 Mar 2021 17:35:30 +0100 Subject: [PATCH 358/384] Increase bounding box for curved elements by 20% in element search tree --- libsrc/meshing/meshclass.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/libsrc/meshing/meshclass.cpp b/libsrc/meshing/meshclass.cpp index 3aff354b..efa24e4a 100644 --- a/libsrc/meshing/meshclass.cpp +++ b/libsrc/meshing/meshclass.cpp @@ -4851,6 +4851,11 @@ namespace netgen for (auto pi : volelements[ei].PNums()) box.Add (points[pi]); + auto & el = volelements[ei]; + if(el.IsCurved()) + box.Increase(1.2*box.Diam()); + + elementsearchtree -> Insert (box, ei+1); } } From bcd86a18fdf741c22227c2cd556b9c8038943a32 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Wed, 17 Mar 2021 17:36:39 +0100 Subject: [PATCH 359/384] FindSurfaceElementOfPoint - use barycentric coordinates of already found volume element Increases robustness for finding curved surface elements --- libsrc/meshing/meshclass.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/libsrc/meshing/meshclass.cpp b/libsrc/meshing/meshclass.cpp index efa24e4a..9ca15f76 100644 --- a/libsrc/meshing/meshclass.cpp +++ b/libsrc/meshing/meshclass.cpp @@ -5712,6 +5712,26 @@ namespace netgen if(faces[i] == 0) continue; + auto & el = VolumeElement(velement); + + if (el.GetType() == TET) + { + double lam4[4] = { vlam[0], vlam[1], vlam[2], 1.0-vlam[0]-vlam[1]-vlam[2] }; + double face_lam = lam4[i]; + if(face_lam < 1e-5) + { + // found volume point very close to a face -> use barycentric coordinates directly + lami[2] = 0.0; + auto sel = SurfaceElement(faces[i]); + + for(auto j : Range(1,3)) + for(auto k : Range(4)) + if(sel[j] == el[k]) + lami[j-1] = lam4[k]/(1.0-face_lam); + return faces[i]; + } + } + if(indices && indices->Size() != 0) { if(indices->Contains(SurfaceElement(faces[i]).GetIndex()) && From a40544ddc58247374cfea69d503b198c7ed318a7 Mon Sep 17 00:00:00 2001 From: Massimiliano Leoni Date: Tue, 23 Mar 2021 12:11:32 +0100 Subject: [PATCH 360/384] Changed integer type of Element::index and Element2d::index --- libsrc/meshing/meshtype.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libsrc/meshing/meshtype.hpp b/libsrc/meshing/meshtype.hpp index 8644b6aa..b3b33cc4 100644 --- a/libsrc/meshing/meshtype.hpp +++ b/libsrc/meshing/meshtype.hpp @@ -406,7 +406,7 @@ namespace netgen PointGeomInfo geominfo[ELEMENT2D_MAXPOINTS]; /// surface nr - short int index; + int index; /// ELEMENT_TYPE typ; /// number of points @@ -738,7 +738,7 @@ namespace netgen }; /// sub-domain index - short int index; + int index; /// order for hp-FEM unsigned int orderx:6; unsigned int ordery:6; From a612444e77d5af8e73caa6dde1693b247d7899b1 Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Tue, 23 Mar 2021 15:08:20 +0100 Subject: [PATCH 361/384] FindElementOfPoint<1> for 2d meshes for curved segments --- libsrc/interface/nginterface_v2.cpp | 9 ++++++ libsrc/meshing/meshclass.cpp | 43 ++++++++++++++++++++++++++++- libsrc/meshing/topology.cpp | 4 ++- libsrc/meshing/topology.hpp | 3 ++ 4 files changed, 57 insertions(+), 2 deletions(-) diff --git a/libsrc/interface/nginterface_v2.cpp b/libsrc/interface/nginterface_v2.cpp index e417be3c..10e8c498 100644 --- a/libsrc/interface/nginterface_v2.cpp +++ b/libsrc/interface/nginterface_v2.cpp @@ -1035,6 +1035,14 @@ namespace netgen case 2: { Point<3> p(hp[0], hp[1],0); + try + { + auto ind = mesh->GetSurfaceElementOfPoint(p, lami, nullptr, + build_searchtree); + return ind - 1; + } + catch(NgException e) // quads not implemented curved yet + { for (SegmentIndex si = 0; si < mesh->GetNSeg(); si++) { auto & seg = (*mesh)[si]; @@ -1058,6 +1066,7 @@ namespace netgen return si; } } + } } break; case 3: diff --git a/libsrc/meshing/meshclass.cpp b/libsrc/meshing/meshclass.cpp index 9ca15f76..4f18c139 100644 --- a/libsrc/meshing/meshclass.cpp +++ b/libsrc/meshing/meshclass.cpp @@ -5268,7 +5268,7 @@ namespace netgen //(*testout) << "col1 " << col1 << " col2 " << col2 << " col3 " << col3 << " rhs " << rhs << endl; //(*testout) << "sol " << sol << endl; - if (SurfaceElement(element).GetType() ==TRIG6) + if (SurfaceElement(element).GetType() ==TRIG6 || curvedelems->IsSurfaceElementCurved(element-1)) { netgen::Point<2> lam(1./3,1./3); Vec<3> rhs; @@ -5679,6 +5679,47 @@ namespace netgen { if (dimension == 2) { + double vlam[3]; + int velement = GetElementOfPoint(p, vlam, NULL, build_searchtree, allowindex); + if(velement == 0) + return 0; + + vlam[2] = 1.-vlam[0] - vlam[1]; + NgArray edges; + topology.GetSurfaceElementEdges(velement, edges); + Array segs(edges.Size()); + for(auto i : Range(edges)) + segs[i] = topology.GetSegmentOfEdge(edges[i]); + + for(auto i : Range(segs)) + { + if(IsInvalid(segs[i])) + continue; + auto& el = SurfaceElement(velement); + if(el.GetType() == TRIG) + { + double seg_lam; + double lam; + auto seg = LineSegment(segs[i]); + for(auto k : Range(3)) + { + if(seg[0] == el[k]) + lam = vlam[k]; + if(seg[1] == el[k]) + seg_lam = vlam[k]; + } + if(1.- seg_lam - lam < 1e-5) + { + // found point close to segment -> use barycentric coordinates directly + lami[0] = lam; + return int(segs[i])+1; + } + } + else + throw NgException("Quad not implemented yet!"); + } + + return 0; throw NgException("GetSurfaceElementOfPoint not yet implemented for 2D meshes"); } else diff --git a/libsrc/meshing/topology.cpp b/libsrc/meshing/topology.cpp index ac571be7..0174d892 100644 --- a/libsrc/meshing/topology.cpp +++ b/libsrc/meshing/topology.cpp @@ -620,7 +620,8 @@ namespace netgen ned += hv; } edge2vert.SetSize(ned); - + edge2segment.SetSize(ned); + edge2segment = -1; // INDEX_CLOSED_HASHTABLE v2eht(2*max_edge_on_vertex+10); // NgArray vertex2; @@ -689,6 +690,7 @@ namespace netgen break; case 1: segedges[elnr].nr = edgenum; + edge2segment[edgenum] = elnr; // segedges[elnr].orient = edgedir; break; } diff --git a/libsrc/meshing/topology.hpp b/libsrc/meshing/topology.hpp index 57205600..53fbc0ff 100644 --- a/libsrc/meshing/topology.hpp +++ b/libsrc/meshing/topology.hpp @@ -63,6 +63,7 @@ class MeshTopology NgArray surffaces; NgArray surf2volelement; NgArray face2surfel; + Array edge2segment; TABLE vert2element; TABLE vert2surfelement; TABLE vert2segment; @@ -169,6 +170,8 @@ public: } int GetFace2SurfaceElement (int fnr) const { return face2surfel[fnr-1]; } + + SegmentIndex GetSegmentOfEdge(int edgenr) const { return edge2segment[edgenr-1]; } void GetVertexElements (int vnr, NgArray & elements) const; NgFlatArray GetVertexElements (int vnr) const From 6cdeaf2d40a36429bc43f94e2bf808e9691193f0 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Tue, 23 Mar 2021 17:52:00 +0100 Subject: [PATCH 362/384] Only add segment end points of 2d geometry to mesh as 0D-elements --- libsrc/geom2d/genmesh2d.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libsrc/geom2d/genmesh2d.cpp b/libsrc/geom2d/genmesh2d.cpp index 5cb9fa58..2ba08b9c 100644 --- a/libsrc/geom2d/genmesh2d.cpp +++ b/libsrc/geom2d/genmesh2d.cpp @@ -271,6 +271,7 @@ namespace netgen // add point elements for (auto & point : geompoints) + if (point.name.length()) { Point<3> newp(point(0), point(1), 0); PointIndex npi = mesh2d.AddPoint (newp, 1, FIXEDPOINT); @@ -301,6 +302,11 @@ namespace netgen { npi = mesh2d.AddPoint (newp, layer); searchtree.Insert (newp, npi); + mesh2d.AddLockedPoint(npi); + Element0d el(npi, npi); + el.name = ""; + mesh2d.SetCD2Name(npi, ""); + mesh2d.pointelements.Append (el); } } } From b431a07c741613cff16895d3423401a6849f6612 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Wed, 24 Mar 2021 12:03:40 +0100 Subject: [PATCH 363/384] Fix starting point for intersection searching --- libsrc/geom2d/csg2d.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libsrc/geom2d/csg2d.cpp b/libsrc/geom2d/csg2d.cpp index 99a45b65..f43d2cb0 100644 --- a/libsrc/geom2d/csg2d.cpp +++ b/libsrc/geom2d/csg2d.cpp @@ -804,8 +804,8 @@ void ComputeIntersections(Edge edgeP , Loop & l2) { for (Edge edgeQ : l2.Edges(SOURCE)) { - double alpha = -1; - double beta = -1; + double alpha = -EPSILON; + double beta = -EPSILON; IntersectionType i = intersect(edgeP, edgeQ, alpha, beta); AddIntersectionPoint(edgeP, edgeQ, i, alpha, beta); if(i==X_INTERSECTION && (edgeP.v0->spline || edgeQ.v0->spline)) From 5a0d07ca879e1fa949ca3bd0257e2996debcff7c Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Wed, 24 Mar 2021 12:04:21 +0100 Subject: [PATCH 364/384] set hpref to 0.0 (fixes random values) --- libsrc/geom2d/csg2d.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libsrc/geom2d/csg2d.cpp b/libsrc/geom2d/csg2d.cpp index f43d2cb0..dd8cf21a 100644 --- a/libsrc/geom2d/csg2d.cpp +++ b/libsrc/geom2d/csg2d.cpp @@ -2216,6 +2216,8 @@ shared_ptr CSG2d :: GenerateSplineGeometry() seg->reffak = 1; seg->copyfrom = -1; seg->hmax = ls.maxh; + seg->hpref_left = 0.; + seg->hpref_right = 0.; geo->AppendSegment(seg); } t_segments.Stop(); From 88fd0a9cd35067443a8d73bd4d31f38616e7b1b5 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Fri, 26 Mar 2021 09:13:11 +0100 Subject: [PATCH 365/384] 2d boundary layer - some cleanup, average growth vectors along straight lines --- libsrc/meshing/boundarylayer.cpp | 144 ++++++++++++++++++++++++++----- 1 file changed, 121 insertions(+), 23 deletions(-) diff --git a/libsrc/meshing/boundarylayer.cpp b/libsrc/meshing/boundarylayer.cpp index 315a062e..d1b83033 100644 --- a/libsrc/meshing/boundarylayer.cpp +++ b/libsrc/meshing/boundarylayer.cpp @@ -760,12 +760,6 @@ namespace netgen BitArray segs_done(nseg); segs_done.Clear(); - // map for all segments with same points - // points to pair of SegmentIndex, int - // int is type of other segment, either: - // TODO: recognize "end points" of boundary layer and implement closure properly - Array>, SegmentIndex> segmap(mesh.GetNSeg()); - // moved segments Array moved_segs; @@ -851,20 +845,7 @@ namespace netgen if(si_map[segi.si] == -1) continue; if(!active_boundaries.Test(segi.epgeominfo[0].edgenr)) continue; - segmap[si].Append(make_pair(si, 0)); moved_segs.Append(si); - for(auto sj : Range(mesh.LineSegments())) - { - if(segs_done.Test(sj)) continue; - const auto& segj = mesh[sj]; - if((segi[0] == segj[0] && segi[1] == segj[1]) || - (segi[0] == segj[1] && segi[1] == segj[0])) - { - segs_done.SetBit(sj); - int type = 0; - segmap[si].Append(make_pair(sj, type)); - } - } } // calculate growth vectors (average normal vectors of adjacent segments at each point) @@ -924,6 +905,127 @@ namespace netgen AddDirection(growthvectors[seg[1]], n); } + ////////////////////////////////////////////////////////////////////////// + // average growthvectors along straight lines to avoid overlaps in corners + BitArray points_done(np+1); + points_done.Clear(); + + for(auto si : moved_segs) + { + auto current_seg = mesh[si]; + auto current_si = si; + + auto first = current_seg[0]; + auto current = -1; + auto next = current_seg[1]; + + if(points_done.Test(first)) + continue; + + Array chain; + chain.Append(first); + + // first find closed loops of segments + while(next != current && next != first) + { + current = next; + points_done.SetBit(current); + chain.Append(current); + for(auto sj : meshtopo.GetVertexSegments( current )) + { + if(!active_segments.Test(sj)) + continue; + + if(sj!=current_si) + { + current_si = sj; + current_seg = mesh[sj]; + + next = current_seg[0] + current_seg[1] - current; + break; + } + } + } + + auto ifirst = 0; + auto n = chain.Size(); + + // angle of adjacent segments at points a[i-1], a[i], a[i+1] + auto getAngle = [&mesh, &growthvectors] (FlatArray a, size_t i) + { + auto n = a.Size(); + auto v0 = growthvectors[a[(i+n-1)%n]]; + auto v1 = growthvectors[a[i]]; + auto v2 = growthvectors[a[(i+1)%n]]; + + auto p0 = mesh[a[(i+n-1)%n]]; + auto p1 = mesh[a[i]]; + auto p2 = mesh[a[(i+1)%n]]; + + v0 = p1-p0; + v1 = p2-p1; + + auto angle = abs(atan2(v1[0], v1[1]) - atan2(v0[0], v0[1])); + if(angle>M_PI) + angle = 2*M_PI-angle; + + return angle; + }; + + // find first corner point + while(getAngle(chain, ifirst) < 1e-5 ) + ifirst = (ifirst+1)%n; + + // Copy points of closed loop in correct order, starting with a corner + Array pis(n+1); + pis.Range(0, n-ifirst) = chain.Range(ifirst, n); + pis.Range(n-ifirst, n) = chain.Range(0, n-ifirst); + pis[n] = pis[0]; + + Array lengths(n); + + for(auto i : Range(n)) + lengths[i] = (mesh[pis[(i+1)%n]] - mesh[pis[i]]).Length(); + + auto averageGrowthVectors = [&] (size_t first, size_t last) + { + if(first+1 >= last) + return; + + double total_len = 0.0; + for(auto l : lengths.Range(first, last)) + total_len += l; + + double len = lengths[first]; + auto v0 = growthvectors[pis[first]]; + auto v1 = growthvectors[pis[last]]; + + for(auto i : Range(first+1, last)) + { + auto pi = pis[i]; + growthvectors[pi] = (len/total_len)*v1 + (1.0-len/total_len)*v0; + len += lengths[i]; + } + }; + + auto icurrent = 0; + + while(icurrent average growth vectors between end points + if(icurrent!=ilast) + averageGrowthVectors(icurrent, ilast); + + icurrent = ilast; + } + } + + ////////////////////////////////////////////////////////////////////// // reduce growthvectors where necessary to avoid overlaps/slim regions const auto getSegmentBox = [&] (SegmentIndex segi) { @@ -969,10 +1071,6 @@ namespace netgen if(Dot(n1, growthvectors[seg1[0]])<0) n1 = -n; if(Dot(n1, growthvectors[seg1[1]])<0) n1 = -n; - // check if angle between normal vectors is less than 180 degrees (cant overlap for opposing directions) -// if(n[0]*n1[1]-n[1]*n1[0]<0.0) -// return; - auto p10 = mesh[seg1[0]]; auto p11 = mesh[seg1[1]]; From 001eaa32b6acb995cd579b40f303dcc66288c5b5 Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Mon, 29 Mar 2021 13:55:23 +0200 Subject: [PATCH 366/384] DoArchive for LocalH --- libsrc/core/archive.hpp | 10 ++++++++++ libsrc/meshing/localh.cpp | 12 ++++++++++++ libsrc/meshing/localh.hpp | 12 ++++++++++-- 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/libsrc/core/archive.hpp b/libsrc/core/archive.hpp index 3bab01f3..430262bf 100644 --- a/libsrc/core/archive.hpp +++ b/libsrc/core/archive.hpp @@ -153,6 +153,7 @@ namespace ngcore virtual void NeedsVersion(const std::string& /*unused*/, const std::string& /*unused*/) {} // Pure virtual functions that have to be implemented by In-/OutArchive + virtual Archive & operator & (float & d) = 0; virtual Archive & operator & (double & d) = 0; virtual Archive & operator & (int & i) = 0; virtual Archive & operator & (long & i) = 0; @@ -678,6 +679,8 @@ namespace ngcore BinaryOutArchive& operator=(BinaryOutArchive&&) = delete; using Archive::operator&; + Archive & operator & (float & f) override + { return Write(f); } Archive & operator & (double & d) override { return Write(d); } Archive & operator & (int & i) override @@ -749,6 +752,8 @@ namespace ngcore : BinaryInArchive(std::make_shared(filename)) { ; } using Archive::operator&; + Archive & operator & (float & f) override + { Read(f); return *this; } Archive & operator & (double & d) override { Read(d); return *this; } Archive & operator & (int & i) override @@ -813,6 +818,8 @@ namespace ngcore TextOutArchive(std::make_shared(filename)) { } using Archive::operator&; + Archive & operator & (float & f) override + { *stream << f << '\n'; return *this; } Archive & operator & (double & d) override { *stream << d << '\n'; return *this; } Archive & operator & (int & i) override @@ -864,6 +871,8 @@ namespace ngcore : TextInArchive(std::make_shared(filename)) {} using Archive::operator&; + Archive & operator & (float & f) override + { *stream >> f; return *this; } Archive & operator & (double & d) override { *stream >> d; return *this; } Archive & operator & (int & i) override @@ -924,6 +933,7 @@ namespace ngcore { h = (char*)&hash_value; } using Archive::operator&; + Archive & operator & (float & f) override { return ApplyHash(f); } Archive & operator & (double & d) override { return ApplyHash(d); } Archive & operator & (int & i) override { return ApplyHash(i); } Archive & operator & (short & i) override { return ApplyHash(i); } diff --git a/libsrc/meshing/localh.cpp b/libsrc/meshing/localh.cpp index 32298191..3afe8e25 100644 --- a/libsrc/meshing/localh.cpp +++ b/libsrc/meshing/localh.cpp @@ -23,6 +23,13 @@ namespace netgen hopt = 2 * h2; } + void GradingBox :: DoArchive(Archive& ar) + { + ar & xmid[0] & xmid[1] & xmid[2] & h2 & father & hopt & + flags.cutboundary & flags.isinner & flags.oldcell & flags.pinner; + for(auto i : Range(8)) + ar & childs[i]; + } BlockAllocator GradingBox :: ball(sizeof (GradingBox)); @@ -93,6 +100,11 @@ namespace netgen root->DeleteChilds(); } + void LocalH :: DoArchive(Archive& ar) + { + ar & root & grading & boxes & boundingbox & dimension; + } + void LocalH :: SetH (Point<3> p, double h) { if (dimension == 2) diff --git a/libsrc/meshing/localh.hpp b/libsrc/meshing/localh.hpp index 4f6881a0..caff6540 100644 --- a/libsrc/meshing/localh.hpp +++ b/libsrc/meshing/localh.hpp @@ -44,10 +44,14 @@ namespace netgen /// GradingBox (const double * ax1, const double * ax2); + /// default constructor for Archive + GradingBox() = default; /// void DeleteChilds(); /// + void DoArchive(Archive& ar); + Point<3> PMid() const { return Point<3> (xmid[0], xmid[1], xmid[2]); } double H2() const { return h2; } @@ -78,7 +82,7 @@ namespace netgen /// double grading; /// - NgArray boxes; + Array boxes; /// Box<3> boundingbox; /// octree or quadtree @@ -89,11 +93,15 @@ namespace netgen /// LocalH (const Box<3> & box, double grading, int adimension = 3) : LocalH (box.PMin(), box.PMax(), grading, adimension) { ; } - /// + /// Default ctor for archive + LocalH() = default; + ~LocalH(); /// void Delete(); /// + void DoArchive(Archive& ar); + /// void SetGrading (double agrading) { grading = agrading; } /// void SetH (Point<3> x, double h); From d2dc84b02cb737fa16f31a1b79021e3febb20190 Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Mon, 29 Mar 2021 14:02:00 +0200 Subject: [PATCH 367/384] more stable boundarylayer, also cut prisms at outside --- libsrc/meshing/boundarylayer.cpp | 182 +++++++++++++++++++++++++---- tests/pytest/test_boundarylayer.py | 2 +- 2 files changed, 163 insertions(+), 21 deletions(-) diff --git a/libsrc/meshing/boundarylayer.cpp b/libsrc/meshing/boundarylayer.cpp index d1b83033..dfaeac9f 100644 --- a/libsrc/meshing/boundarylayer.cpp +++ b/libsrc/meshing/boundarylayer.cpp @@ -414,14 +414,14 @@ namespace netgen } } - BitArray fixed_points(np+1); - fixed_points.Clear(); - BitArray moveboundarypoint(np+1); - moveboundarypoint.Clear(); + // 1 if moved away from point, 2 if moved towards point + Array>> fixed_points(np+1); for(SurfaceElementIndex si = 0; si < nse; si++) { // copy because surfaceels array will be resized! auto sel = mesh[si]; + // force move this sel + bool move_sel = false; if(si_map[sel.GetIndex()] != -1) { Array points(sel.PNums()); @@ -448,22 +448,69 @@ namespace netgen } else { - bool has_moved = false; + ArrayMem>, 4> moved_direction; for(auto p : sel.PNums()) if(mapto[p].Size()) - has_moved = true; - if(has_moved) + { + Vec<3> dir = growthvectors[p]; + moved_direction.Append({ p, dir.Normalize() }); + } + const auto& fd = mesh.GetFaceDescriptor(sel.GetIndex()); + bool in_inside = blp.domains.Test(fd.DomainIn()); + bool sel_between_in_and_out = in_inside != blp.domains.Test(fd.DomainOut()); + if(moved_direction.Size() && sel_between_in_and_out) for(auto p : sel.PNums()) { if(!mapto[p].Size()) { - fixed_points.SetBit(p); - if(move_boundaries.Test(sel.GetIndex())) - moveboundarypoint.SetBit(p); + tuple max = { PointIndex::INVALID, 0 }; + for(auto& [po, dir] : moved_direction) + { + Vec<3> mydir = mesh[p] - mesh[po]; + mydir.Normalize(); + double ang = mydir * dir; + if(fabs(ang) >= fabs(get<1>(max))) + max = { po, ang }; + } + fixed_points[p].Append({ get<0>(max), get<1>(max) > 0 }); } } + // if only one point is moved and moved into sel + // then sel needs to be divided + if(!sel_between_in_and_out && !in_inside && moved_direction.Size() == 1) + { + for(const auto& p : sel.PNums()) + { + if(!mapto[p].Size()) + { + const auto& [po, dir] = moved_direction[0]; + Vec<3> mydir = mesh[p] - mesh[po]; + mydir.Normalize(); + if(mydir * dir > 1 - 1e-6) + { + PointIndex p1 = po; + for(auto i : Range(blp.heights)) + { + PointIndex p2 = mapto[po][i]; + Element2d newel = sel; + for(auto& pi : newel.PNums()) + { + if(pi == po) + pi = p1; + if(pi == p) + pi = p2; + } + p1 = p2; + newel.SetIndex(sel.GetIndex()); + mesh.AddSurfaceElement(newel); + move_sel = true; + } + } + } + } + } } - if(move_boundaries.Test(sel.GetIndex())) + if(move_sel || move_boundaries.Test(sel.GetIndex())) { for(auto& p : mesh[si].PNums()) if(mapto[p].Size()) @@ -484,28 +531,65 @@ namespace netgen { auto el = mesh[ei]; ArrayMem fixed; + ArrayMem fixed_other; ArrayMem moved; bool moved_bnd = false; for(const auto& p : el.PNums()) { - if(fixed_points.Test(p)) - fixed.Append(p); + if(domains.Test(el.GetIndex())) + { + if(fixed_points[p].Size()) + { + bool found = false; + bool found_other = false; + for(const auto& tup : fixed_points[p]) + if(get<1>(tup)) + { + found_other = true; + if(el.PNums().Contains(get<0>(tup))) + found = true; + } + if(found_other) + fixed_other.Append(p); + if(found) + fixed.Append(p); + } + } + if(!domains.Test(el.GetIndex())) + { + if(fixed_points[p].Size()) + { + bool found = false; + bool found_other = false; + for(const auto& tup : fixed_points[p]) + { + if(!get<1>(tup)) + { + found_other = true; + if(el.PNums().Contains(get<0>(tup))) + found = true; + } + } + if(found) + fixed.Append(p); + if(found_other) + fixed_other.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_move = fixed.Size() && moved.Size(); do_insert = do_move; } else { - do_move = !fixed.Size() || moved_bnd; - do_insert = !do_move; + do_move = !fixed.Size() && moved.Size(); + do_insert = !do_move && moved.Size(); } if(do_move) @@ -576,9 +660,9 @@ namespace netgen for(auto& p : nel.PNums()) { if(p == moved[0]) - p = p1; + p = domains.Test(el.GetIndex()) ? p1 : p2; else if(p == fixed[0]) - p = p2; + p = domains.Test(el.GetIndex()) ? p2 : p1; } p1 = p2; mesh.AddVolumeElement(nel); @@ -614,6 +698,64 @@ namespace netgen else if(moved.Size() == 1) throw Exception("This case is not implemented yet!"); } + else if(el.GetType() == PRISM) + { + if(moved.Size() == 2) + { + auto pnums = el.PNums(); + bool cut_vertical = (moved[0] == pnums[0] && moved[1] == pnums[3]) || (moved[0] == pnums[1] && moved[1] == pnums[4]) || (moved[0] == pnums[2] && moved[1] == pnums[5]); + if(cut_vertical) + { + if(fixed.Size() != 2) + { + cout << "in domain = " << domains.Test(el.GetIndex()) << endl; + cout << "moved = " << moved << endl; + cout << "fixed = " << fixed << endl; + cout << "pnums = " << el.PNums() << endl; + throw Exception("Cut prism vert only implemented for fixed size == 2!"); + } + auto bot_trig = pnums.Range(3); + if(bot_trig.Contains(moved[1])) + Swap(moved[0], moved[1]); + if(bot_trig.Contains(fixed[1])) + Swap(fixed[0], fixed[1]); + + PointIndex tip_bot = pnums[0] + pnums[1] + pnums[2] - moved[0] - fixed[0]; + PointIndex tip_top = pnums[3] + pnums[4] + pnums[5] - moved[1] - fixed[1]; + int index_moved = bot_trig.Pos(moved[0]); + int index_tip = bot_trig.Pos(tip_bot); + int index_fixed = 3 - index_moved - index_tip; + PointIndex p1_bot = moved[0]; + PointIndex p1_top = moved[1]; + for(auto i : Range(blp.heights)) + { + PointIndex p2_bot = mapto[moved[0]][i]; + PointIndex p2_top = mapto[moved[1]][i]; + Element nel(PRISM); + nel[index_moved] = p1_bot; + nel[index_tip] = tip_bot; + nel[index_fixed] = p2_bot; + nel[3+index_moved] = p1_top; + nel[3+index_tip] = tip_top; + nel[3+index_fixed] = p2_top; + nel.SetIndex(el.GetIndex()); + mesh.AddVolumeElement(nel); + p1_bot = p2_bot; + p1_top = p2_top; + } + } + else + throw Exception("Boundarylayer horizontally threw PRISM not implemented yet!"); + } + else + { + cout << "in domain = " << domains.Test(el.GetIndex()) << endl; + cout << "moved = " << moved << endl; + cout << "fixed = " << fixed << endl; + cout << "pnums = " << el.PNums() << endl; + throw Exception("Prism with moved points != 2 not implemented yet!"); + } + } else throw Exception("Boundarylayer only implemented for tets and pyramids outside yet!"); } diff --git a/tests/pytest/test_boundarylayer.py b/tests/pytest/test_boundarylayer.py index 798cb1cc..f5eeb679 100644 --- a/tests/pytest/test_boundarylayer.py +++ b/tests/pytest/test_boundarylayer.py @@ -33,7 +33,7 @@ def test_boundarylayer(outside, capfd): assert not "elements are not matching" in capture.out @pytest.mark.parametrize("outside", [True, False]) -@pytest.mark.parametrize("version", [1, 2]) # version 2 not working yet +@pytest.mark.parametrize("version", [1, 2]) def test_boundarylayer2(outside, version, capfd): geo = CSGeometry() top = Plane(Pnt(0,0,0.5), Vec(0,0,1)) From 15380a2618139d75eaa3371ce424ea34d694364b Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Mon, 29 Mar 2021 18:05:09 +0200 Subject: [PATCH 368/384] Revert "more stable boundarylayer, also cut prisms at outside" This reverts commit d2dc84b02cb737fa16f31a1b79021e3febb20190. --- libsrc/meshing/boundarylayer.cpp | 182 ++++------------------------- tests/pytest/test_boundarylayer.py | 2 +- 2 files changed, 21 insertions(+), 163 deletions(-) diff --git a/libsrc/meshing/boundarylayer.cpp b/libsrc/meshing/boundarylayer.cpp index dfaeac9f..d1b83033 100644 --- a/libsrc/meshing/boundarylayer.cpp +++ b/libsrc/meshing/boundarylayer.cpp @@ -414,14 +414,14 @@ namespace netgen } } - // 1 if moved away from point, 2 if moved towards point - Array>> fixed_points(np+1); + BitArray fixed_points(np+1); + fixed_points.Clear(); + BitArray moveboundarypoint(np+1); + moveboundarypoint.Clear(); for(SurfaceElementIndex si = 0; si < nse; si++) { // copy because surfaceels array will be resized! auto sel = mesh[si]; - // force move this sel - bool move_sel = false; if(si_map[sel.GetIndex()] != -1) { Array points(sel.PNums()); @@ -448,69 +448,22 @@ namespace netgen } else { - ArrayMem>, 4> moved_direction; + bool has_moved = false; for(auto p : sel.PNums()) if(mapto[p].Size()) - { - Vec<3> dir = growthvectors[p]; - moved_direction.Append({ p, dir.Normalize() }); - } - const auto& fd = mesh.GetFaceDescriptor(sel.GetIndex()); - bool in_inside = blp.domains.Test(fd.DomainIn()); - bool sel_between_in_and_out = in_inside != blp.domains.Test(fd.DomainOut()); - if(moved_direction.Size() && sel_between_in_and_out) + has_moved = true; + if(has_moved) for(auto p : sel.PNums()) { if(!mapto[p].Size()) { - tuple max = { PointIndex::INVALID, 0 }; - for(auto& [po, dir] : moved_direction) - { - Vec<3> mydir = mesh[p] - mesh[po]; - mydir.Normalize(); - double ang = mydir * dir; - if(fabs(ang) >= fabs(get<1>(max))) - max = { po, ang }; - } - fixed_points[p].Append({ get<0>(max), get<1>(max) > 0 }); + fixed_points.SetBit(p); + if(move_boundaries.Test(sel.GetIndex())) + moveboundarypoint.SetBit(p); } } - // if only one point is moved and moved into sel - // then sel needs to be divided - if(!sel_between_in_and_out && !in_inside && moved_direction.Size() == 1) - { - for(const auto& p : sel.PNums()) - { - if(!mapto[p].Size()) - { - const auto& [po, dir] = moved_direction[0]; - Vec<3> mydir = mesh[p] - mesh[po]; - mydir.Normalize(); - if(mydir * dir > 1 - 1e-6) - { - PointIndex p1 = po; - for(auto i : Range(blp.heights)) - { - PointIndex p2 = mapto[po][i]; - Element2d newel = sel; - for(auto& pi : newel.PNums()) - { - if(pi == po) - pi = p1; - if(pi == p) - pi = p2; - } - p1 = p2; - newel.SetIndex(sel.GetIndex()); - mesh.AddSurfaceElement(newel); - move_sel = true; - } - } - } - } - } } - if(move_sel || move_boundaries.Test(sel.GetIndex())) + if(move_boundaries.Test(sel.GetIndex())) { for(auto& p : mesh[si].PNums()) if(mapto[p].Size()) @@ -531,65 +484,28 @@ namespace netgen { auto el = mesh[ei]; ArrayMem fixed; - ArrayMem fixed_other; ArrayMem moved; bool moved_bnd = false; for(const auto& p : el.PNums()) { - if(domains.Test(el.GetIndex())) - { - if(fixed_points[p].Size()) - { - bool found = false; - bool found_other = false; - for(const auto& tup : fixed_points[p]) - if(get<1>(tup)) - { - found_other = true; - if(el.PNums().Contains(get<0>(tup))) - found = true; - } - if(found_other) - fixed_other.Append(p); - if(found) - fixed.Append(p); - } - } - if(!domains.Test(el.GetIndex())) - { - if(fixed_points[p].Size()) - { - bool found = false; - bool found_other = false; - for(const auto& tup : fixed_points[p]) - { - if(!get<1>(tup)) - { - found_other = true; - if(el.PNums().Contains(get<0>(tup))) - found = true; - } - } - if(found) - fixed.Append(p); - if(found_other) - fixed_other.Append(p); - } - } + 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.Size(); + do_move = fixed.Size() && moved_bnd; do_insert = do_move; } else { - do_move = !fixed.Size() && moved.Size(); - do_insert = !do_move && moved.Size(); + do_move = !fixed.Size() || moved_bnd; + do_insert = !do_move; } if(do_move) @@ -660,9 +576,9 @@ namespace netgen for(auto& p : nel.PNums()) { if(p == moved[0]) - p = domains.Test(el.GetIndex()) ? p1 : p2; + p = p1; else if(p == fixed[0]) - p = domains.Test(el.GetIndex()) ? p2 : p1; + p = p2; } p1 = p2; mesh.AddVolumeElement(nel); @@ -698,64 +614,6 @@ namespace netgen else if(moved.Size() == 1) throw Exception("This case is not implemented yet!"); } - else if(el.GetType() == PRISM) - { - if(moved.Size() == 2) - { - auto pnums = el.PNums(); - bool cut_vertical = (moved[0] == pnums[0] && moved[1] == pnums[3]) || (moved[0] == pnums[1] && moved[1] == pnums[4]) || (moved[0] == pnums[2] && moved[1] == pnums[5]); - if(cut_vertical) - { - if(fixed.Size() != 2) - { - cout << "in domain = " << domains.Test(el.GetIndex()) << endl; - cout << "moved = " << moved << endl; - cout << "fixed = " << fixed << endl; - cout << "pnums = " << el.PNums() << endl; - throw Exception("Cut prism vert only implemented for fixed size == 2!"); - } - auto bot_trig = pnums.Range(3); - if(bot_trig.Contains(moved[1])) - Swap(moved[0], moved[1]); - if(bot_trig.Contains(fixed[1])) - Swap(fixed[0], fixed[1]); - - PointIndex tip_bot = pnums[0] + pnums[1] + pnums[2] - moved[0] - fixed[0]; - PointIndex tip_top = pnums[3] + pnums[4] + pnums[5] - moved[1] - fixed[1]; - int index_moved = bot_trig.Pos(moved[0]); - int index_tip = bot_trig.Pos(tip_bot); - int index_fixed = 3 - index_moved - index_tip; - PointIndex p1_bot = moved[0]; - PointIndex p1_top = moved[1]; - for(auto i : Range(blp.heights)) - { - PointIndex p2_bot = mapto[moved[0]][i]; - PointIndex p2_top = mapto[moved[1]][i]; - Element nel(PRISM); - nel[index_moved] = p1_bot; - nel[index_tip] = tip_bot; - nel[index_fixed] = p2_bot; - nel[3+index_moved] = p1_top; - nel[3+index_tip] = tip_top; - nel[3+index_fixed] = p2_top; - nel.SetIndex(el.GetIndex()); - mesh.AddVolumeElement(nel); - p1_bot = p2_bot; - p1_top = p2_top; - } - } - else - throw Exception("Boundarylayer horizontally threw PRISM not implemented yet!"); - } - else - { - cout << "in domain = " << domains.Test(el.GetIndex()) << endl; - cout << "moved = " << moved << endl; - cout << "fixed = " << fixed << endl; - cout << "pnums = " << el.PNums() << endl; - throw Exception("Prism with moved points != 2 not implemented yet!"); - } - } else throw Exception("Boundarylayer only implemented for tets and pyramids outside yet!"); } diff --git a/tests/pytest/test_boundarylayer.py b/tests/pytest/test_boundarylayer.py index f5eeb679..798cb1cc 100644 --- a/tests/pytest/test_boundarylayer.py +++ b/tests/pytest/test_boundarylayer.py @@ -33,7 +33,7 @@ def test_boundarylayer(outside, capfd): assert not "elements are not matching" in capture.out @pytest.mark.parametrize("outside", [True, False]) -@pytest.mark.parametrize("version", [1, 2]) +@pytest.mark.parametrize("version", [1, 2]) # version 2 not working yet def test_boundarylayer2(outside, version, capfd): geo = CSGeometry() top = Plane(Pnt(0,0,0.5), Vec(0,0,1)) From 1f4560138756785224156e5e8651a69027159700 Mon Sep 17 00:00:00 2001 From: Joachim Schoeberl Date: Mon, 29 Mar 2021 22:39:50 +0200 Subject: [PATCH 369/384] Array ia(n); ia.Range(2, END-1) --- libsrc/core/array.hpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/libsrc/core/array.hpp b/libsrc/core/array.hpp index d47e4b78..1875f38f 100644 --- a/libsrc/core/array.hpp +++ b/libsrc/core/array.hpp @@ -212,6 +212,20 @@ namespace ngcore template constexpr T IndexBASE () { return T(0); } + + class IndexFromEnd + { + ptrdiff_t i; + public: + constexpr IndexFromEnd (ptrdiff_t ai) : i(ai) { } + IndexFromEnd operator+ (ptrdiff_t inc) const { return i+inc; } + IndexFromEnd operator- (ptrdiff_t dec) const { return i-dec; } + // operator ptrdiff_t () const { return i; } + ptrdiff_t Value() const { return i; } + }; + + constexpr IndexFromEnd END(0); + template class FlatArray; @@ -560,6 +574,12 @@ namespace ngcore return FlatArray (end-start, data+start); } + /// takes range starting from position start of end-start elements + NETGEN_INLINE FlatArray Range (size_t start, IndexFromEnd indend) const + { + return this->Range(start, size_t(Size()+indend.Value())); + } + /// takes range starting from position start of end-start elements NETGEN_INLINE FlatArray Range (T_Range range) const { From 44c10f663a3dc43b37a809b4ad47f30a1c4ed80e Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Tue, 30 Mar 2021 16:54:39 +0200 Subject: [PATCH 370/384] Boundarylayer 2d interface --- libsrc/meshing/boundarylayer.cpp | 73 ++++++++++++++++++++++---------- libsrc/meshing/boundarylayer.hpp | 2 +- 2 files changed, 52 insertions(+), 23 deletions(-) diff --git a/libsrc/meshing/boundarylayer.cpp b/libsrc/meshing/boundarylayer.cpp index d1b83033..3c4b3951 100644 --- a/libsrc/meshing/boundarylayer.cpp +++ b/libsrc/meshing/boundarylayer.cpp @@ -743,8 +743,10 @@ namespace netgen } - void GenerateBoundaryLayer2 (Mesh & mesh, int domain, const Array & boundaries, const Array & thicknesses) + int GenerateBoundaryLayer2 (Mesh & mesh, int domain, const Array & thicknesses, bool should_make_new_domain, const Array & boundaries) { + SegmentIndex first_new_seg = mesh.LineSegments().Range().Next(); + int np = mesh.GetNP(); int nseg = mesh.GetNSeg(); int ne = mesh.GetNSE(); @@ -800,6 +802,8 @@ namespace netgen max_domain = seg.si; } + int new_domain = max_domain+1; + BitArray active_boundaries(max_edge_nr+1); BitArray active_segments(nseg); active_boundaries.Clear(); @@ -829,12 +833,12 @@ namespace netgen if(!active_segments.Test(segi)) continue; - int new_si = mesh.GetNFD()+1; - FaceDescriptor new_fd(-1, 0, 0, -1); - new_fd.SetBCProperty(new_si); - mesh.AddFaceDescriptor(new_fd); - si_map[si] = new_si; - mesh.SetBCName(new_si-1, "mapped_" + mesh.GetBCName(si-1)); + FaceDescriptor new_fd(0, 0, 0, -1); + new_fd.SetBCProperty(new_domain); + int new_fd_index = mesh.AddFaceDescriptor(new_fd); + si_map[si] = new_domain; + if(should_make_new_domain) + mesh.SetBCName(new_domain-1, "mapped_" + mesh.GetBCName(si-1)); } for(auto si : Range(mesh.LineSegments())) @@ -1210,22 +1214,22 @@ namespace netgen auto newindex = si_map[seg.si]; - { - Segment s = seg; - s[0] = pm0.Last(); - s[1] = pm1.Last(); - s[2] = PointIndex::INVALID; - auto pair = s[0] < s[1] ? make_pair(s[0], s[1]) : make_pair(s[1], s[0]); - if(seg2edge.find(pair) == seg2edge.end()) - seg2edge[pair] = ++max_edge_nr; - s.edgenr = seg2edge[pair]; - s.si = seg.si; - mesh.AddSegment(s); + Segment s = seg; + s.geominfo[0] = {}; + s.geominfo[1] = {}; + s[0] = pm0.Last(); + s[1] = pm1.Last(); + s[2] = PointIndex::INVALID; + auto pair = s[0] < s[1] ? make_pair(s[0], s[1]) : make_pair(s[1], s[0]); + if(seg2edge.find(pair) == seg2edge.end()) + seg2edge[pair] = ++max_edge_nr; + s.edgenr = seg2edge[pair]; + s.si = seg.si; + mesh.AddSegment(s); - Swap(s[0], s[1]); - s.si = newindex; - mesh.AddSegment(s); - } + Swap(s[0], s[1]); + s.si = newindex; + mesh.AddSegment(s); for ( auto i : Range(thicknesses)) { @@ -1265,6 +1269,7 @@ namespace netgen newel[2] = pi2; newel[3] = pi3; newel.SetIndex(si_map[seg.si]); + newel.GeomInfo() = PointGeomInfo{}; // if(swap) // { @@ -1306,6 +1311,30 @@ namespace netgen mesh.CalcSurfacesOfNode(); Generate2dMesh(mesh, domain); + + // even without new domain, we need temporarily a new domain to mesh the remaining area, without confusing the meshes with quads -> add segments temporarily and reset domain number and segments afterwards + if(!should_make_new_domain) + { + // map new domain back to old one + for(auto & sel : mesh.SurfaceElements()) + if(sel.GetIndex()==new_domain) + sel.SetIndex(domain); + + // remove (temporary) inner segments + for(auto segi : Range(first_new_seg, mesh.LineSegments().Range().Next())) + { + mesh[segi][0].Invalidate(); + mesh[segi][1].Invalidate(); + } + + for(auto segi : moved_segs) + mesh[segi].si = domain; + + mesh.Compress(); + mesh.CalcSurfacesOfNode(); + } + + return new_domain; } } diff --git a/libsrc/meshing/boundarylayer.hpp b/libsrc/meshing/boundarylayer.hpp index 9e78a13d..4d61276b 100644 --- a/libsrc/meshing/boundarylayer.hpp +++ b/libsrc/meshing/boundarylayer.hpp @@ -24,6 +24,6 @@ public: DLL_HEADER void GenerateBoundaryLayer (Mesh & mesh, const BoundaryLayerParameters & blp); -DLL_HEADER void GenerateBoundaryLayer2 (Mesh & mesh, int domain, const Array & boundaries, const Array & thicknesses); +DLL_HEADER int /* new_domain_number */ GenerateBoundaryLayer2 (Mesh & mesh, int domain, const Array & thicknesses, bool should_make_new_domain=true, const Array & boundaries=Array{}); #endif From 096b419f6e860546c32daa25c3979a1f772d4706 Mon Sep 17 00:00:00 2001 From: Joachim Schoeberl Date: Wed, 31 Mar 2021 07:50:18 +0200 Subject: [PATCH 371/384] parent edges for red refinement (thx Guosheng) --- libsrc/meshing/refine.cpp | 6 +- libsrc/meshing/topology.cpp | 436 +++++++++++++++++++++--------------- 2 files changed, 259 insertions(+), 183 deletions(-) diff --git a/libsrc/meshing/refine.cpp b/libsrc/meshing/refine.cpp index 5c92a95d..b9d06c16 100644 --- a/libsrc/meshing/refine.cpp +++ b/libsrc/meshing/refine.cpp @@ -34,6 +34,9 @@ namespace netgen mesh.mlbetweennodes = INDEX_2(PointIndex::BASE-1,PointIndex::BASE-1); } + if (mesh.level_nv.Size() == 0) + mesh.level_nv.Append (mesh.GetNV()); + INDEX_2_HASHTABLE between(mesh.GetNP() + 5); @@ -739,6 +742,7 @@ namespace netgen mesh.ComputeNVertices(); mesh.RebuildSurfaceElementLists(); + mesh.level_nv.Append (mesh.GetNV()); #ifdef PARALLEL if (mesh.GetCommunicator().Size() > 1) @@ -748,7 +752,7 @@ namespace netgen mesh.GetParallelTopology().EnumeratePointsGlobally(); } #endif - + PrintMessage (5, "mesh updates complete"); return; diff --git a/libsrc/meshing/topology.cpp b/libsrc/meshing/topology.cpp index 0174d892..d649b23a 100644 --- a/libsrc/meshing/topology.cpp +++ b/libsrc/meshing/topology.cpp @@ -699,196 +699,268 @@ namespace netgen } ); - if (build_parent_edges) - { - static Timer t("build_hierarchy"); RegionTimer reg(t); - cnt = 0; - for (auto verts : edge2vert) cnt[verts[0]]++; - TABLE vert2edge (cnt); - for (auto i : edge2vert.Range()) - vert2edge.AddSave (edge2vert[i][0], i); - - // build edge hierarchy: - parent_edges.SetSize (ned); - parent_edges = { -1, { -1, -1, -1 } }; + if (build_parent_edges) + { + static Timer t("build_hierarchy"); RegionTimer reg(t); + cnt = 0; + for (auto verts : edge2vert) cnt[verts[0]]++; + TABLE vert2edge (cnt); + for (auto i : edge2vert.Range()) + vert2edge.AddSave (edge2vert[i][0], i); - for (size_t i = 0; i < ned; i++) - { - auto verts = edge2vert[i]; // 2 vertices of edge + // build edge hierarchy: + parent_edges.SetSize (ned); + parent_edges = { -1, { -1, -1, -1 } }; - if (verts[0] >= mesh->mlbetweennodes.Size()+PointIndex::BASE || - verts[1] >= mesh->mlbetweennodes.Size()+PointIndex::BASE) - continue; - - auto pa0 = mesh->mlbetweennodes[verts[0]]; // two parent vertices of v0 - auto pa1 = mesh->mlbetweennodes[verts[1]]; // two parent vertices of v1 + for (size_t i = 0; i < ned; i++) + { + auto verts = edge2vert[i]; // 2 vertices of edge - // both vertices are on coarsest mesh - if (!pa0[0].IsValid() && !pa1[0].IsValid()) - continue; - - int issplitedge = 0; - if (pa0[0] == verts[1] || pa0[1] == verts[1]) - issplitedge = 1; - if (pa1[0] == verts[0] || pa1[1] == verts[0]) - issplitedge = 2; - - if (issplitedge) - { - // cout << "split edge " << endl; - // edge is obtained by splitting one edge into two parts: - auto paedge = issplitedge == 1 ? pa0 : pa1; - - if (paedge[0] > paedge[1]) - Swap (paedge[0], paedge[1]); - - for (int ednr : vert2edge[paedge[0]]) - if (auto cverts = edge2vert[ednr]; cverts[1] == paedge[1]) - { - int orient = (paedge[0] == verts[0] || paedge[1] == verts[1]) ? 1 : 0; - parent_edges[i] = { orient, { ednr, -1, -1 } }; - } - } - else - { - // edge is splitting edge in middle of triangle: - for (int j = 1; j <= 2; j++) - { - INT<2> paedge1, paedge2, paedge3; - int orient_inner = 0; - if (j == 1) - { - paedge1 = INT<2> (pa0[0], verts[1]); - paedge2 = INT<2> (pa0[1], verts[1]); - paedge3 = INT<2> (pa0[0], pa0[1]); - orient_inner = 0; - } - else - { - paedge1 = INT<2> (pa1[0], verts[0]); - paedge2 = INT<2> (pa1[1], verts[0]); - paedge3 = INT<2> (pa1[0], pa1[1]); - orient_inner = 1; - } - if (paedge1[0] > paedge1[1]) - Swap (paedge1[0], paedge1[1]); - if (paedge2[0] > paedge2[1]) - Swap (paedge2[0], paedge2[1]); - if (paedge3[0] > paedge3[1]) - Swap (paedge3[0], paedge3[1]); - - // if first vertex number is -1, then don't try to find entry in node2edge hash table - if ( paedge1[0] == PointIndex::BASE-1 || paedge2[0] == PointIndex::BASE-1 ) - continue; + if (verts[0] >= mesh->mlbetweennodes.Size()+PointIndex::BASE || + verts[1] >= mesh->mlbetweennodes.Size()+PointIndex::BASE) + continue; - int paedgenr1=-1, paedgenr2=-1, paedgenr3=-1, orient1 = 0, orient2 = 0; - for (int ednr : vert2edge[paedge1[0]]) - if (auto cverts = edge2vert[ednr]; cverts[1] == paedge1[1]) - { - paedgenr1 = ednr; - orient1 = (paedge1[0] == verts[0] || paedge1[1] == verts[1]) ? 1 : 0; - } - for (int ednr : vert2edge[paedge2[0]]) - if (auto cverts = edge2vert[ednr]; cverts[1] == paedge2[1]) - { - paedgenr2 = ednr; - orient2 = (paedge2[0] == verts[0] || paedge2[1] == verts[1]) ? 1 : 0; - } - - for (int ednr : vert2edge[paedge3[0]]) - if (auto cverts = edge2vert[ednr]; cverts[1] == paedge3[1]) - paedgenr3 = ednr; - - if (paedgenr1 != -1 && paedgenr2 != -1) - parent_edges[i] = { orient1+2*orient2+4*orient_inner, { paedgenr1, paedgenr2, paedgenr3 } }; - } + auto pa0 = mesh->mlbetweennodes[verts[0]]; // two parent vertices of v0 + auto pa1 = mesh->mlbetweennodes[verts[1]]; // two parent vertices of v1 + + // both vertices are on coarsest mesh + if (!pa0[0].IsValid() && !pa1[0].IsValid()) + continue; + + int issplitedge = 0; + if (pa0[0] == verts[1] || pa0[1] == verts[1]) + issplitedge = 1; + if (pa1[0] == verts[0] || pa1[1] == verts[0]) + issplitedge = 2; + + if (issplitedge) + { + // cout << "split edge " << endl; + // edge is obtained by splitting one edge into two parts: + auto paedge = issplitedge == 1 ? pa0 : pa1; + + if (paedge[0] > paedge[1]) + Swap (paedge[0], paedge[1]); + + for (int ednr : vert2edge[paedge[0]]) + if (auto cverts = edge2vert[ednr]; cverts[1] == paedge[1]) + { + int orient = (paedge[0] == verts[0] || paedge[1] == verts[1]) ? 1 : 0; + parent_edges[i] = { orient, { ednr, -1, -1 } }; + } + } + else + { + bool bisect_edge = false; + // edge is splitting edge in middle of triangle: + for (int j = 1; j <= 2; j++) + { + INT<2> paedge1, paedge2, paedge3; + int orient_inner = 0; + if (j == 1) + { + paedge1 = INT<2> (pa0[0], verts[1]); + paedge2 = INT<2> (pa0[1], verts[1]); + paedge3 = INT<2> (pa0[0], pa0[1]); + orient_inner = 0; + } + else + { + paedge1 = INT<2> (pa1[0], verts[0]); + paedge2 = INT<2> (pa1[1], verts[0]); + paedge3 = INT<2> (pa1[0], pa1[1]); + orient_inner = 1; + } + if (paedge1[0] > paedge1[1]) + Swap (paedge1[0], paedge1[1]); + if (paedge2[0] > paedge2[1]) + Swap (paedge2[0], paedge2[1]); + if (paedge3[0] > paedge3[1]) + Swap (paedge3[0], paedge3[1]); + + // if first vertex number is -1, then don't try to find entry in node2edge hash table + if ( paedge1[0] == PointIndex::BASE-1 || paedge2[0] == PointIndex::BASE-1 ) + continue; + + int paedgenr1=-1, paedgenr2=-1, paedgenr3=-1, orient1 = 0, orient2 = 0; + for (int ednr : vert2edge[paedge1[0]]) + if (auto cverts = edge2vert[ednr]; cverts[1] == paedge1[1]) + { + paedgenr1 = ednr; + orient1 = (paedge1[0] == verts[0] || paedge1[1] == verts[1]) ? 1 : 0; + } + for (int ednr : vert2edge[paedge2[0]]) + if (auto cverts = edge2vert[ednr]; cverts[1] == paedge2[1]) + { + paedgenr2 = ednr; + orient2 = (paedge2[0] == verts[0] || paedge2[1] == verts[1]) ? 1 : 0; + } + + for (int ednr : vert2edge[paedge3[0]]) + if (auto cverts = edge2vert[ednr]; cverts[1] == paedge3[1]) + paedgenr3 = ednr; + + if (paedgenr1 != -1 && paedgenr2 != -1){ + bisect_edge = true; + parent_edges[i] = { orient1+2*orient2+4*orient_inner, { paedgenr1, paedgenr2, paedgenr3 } }; + } + } + + if (!bisect_edge) // not a bisect edge (then a red edge) + { + INT<2> paedge1, paedge2, paedge3; + int orient1 = 0, orient2 = 0, orient3=0; + int orient_inner = 0; + paedge1 = INT<2> (pa0[0], pa0[1]); + paedge2 = INT<2> (pa1[0], pa1[1]); + // find common vertex and the thrid pa edge + if (pa0[0]==pa1[0]){// 00 + //orient1 = 0; + orient2 = 1; + if (pa0[1] (pa0[1], pa1[1]); + }else{ + //orient3 = 0; + paedge3 = INT<2> (pa1[1], pa0[1]); + } + } + else if (pa0[0]==pa1[1]){//01 + //orient1 = 0; + //orient2 = 0; + if (pa0[1] (pa0[1], pa1[0]); + }else{ + //orient3 = 0; + paedge3 = INT<2> (pa1[0], pa0[1]); + } + } + else if (pa0[1]==pa1[0]){//10 + orient1 = 1; + orient2 = 1; + if (pa0[0] (pa0[0], pa1[1]); + }else{ + //orient3 = 0; + paedge3 = INT<2> (pa1[1], pa0[0]); + } + } + else if (pa0[1]==pa1[1]){//11 + orient1 = 1; + //orient2 = 0; + if (pa0[0] (pa0[0], pa1[0]); + }else{ + //orient3 = 0; + paedge3 = INT<2> (pa1[0], pa0[0]); + } + } + + int paedgenr1=-1, paedgenr2=-1, paedgenr3=-1; + for (int ednr : vert2edge[paedge1[0]]) + if (auto cverts = edge2vert[ednr]; cverts[1] == paedge1[1]) + paedgenr1 = ednr; + for (int ednr : vert2edge[paedge2[0]]) + if (auto cverts = edge2vert[ednr]; cverts[1] == paedge2[1]) + paedgenr2 = ednr; + + for (int ednr : vert2edge[paedge3[0]]) + if (auto cverts = edge2vert[ednr]; cverts[1] == paedge3[1]) + paedgenr3 = ednr; + + parent_edges[i] = { 8+orient1+2*orient2+4*orient3, { paedgenr1, paedgenr2, paedgenr3 } }; + + //cout <<8+orient1+2*orient2+4*orient3 <<":"< paedge1, paedge2; - if (j == 1) - { - paedge1 = INT<2> (pa1[0], pa2[0]); - paedge2 = INT<2> (pa1[1], pa2[1]); - } - else - { - paedge1 = INT<2> (pa1[0], pa2[1]); - paedge2 = INT<2> (pa1[1], pa2[0]); - } - - int paedgenr1 = 0, paedgenr2 = 0; - int orient1 = 1, orient2 = 1; - - if (paedge1[0] > paedge1[1]) - { - Swap (paedge1[0], paedge1[1]); - orient1 = 0; - } - if (paedge2[0] > paedge2[1]) - { - Swap (paedge2[0], paedge2[1]); - orient2 = 0; - } - - if ( paedge1[0] == -1 || paedge2[0] == -1 ) - continue; - - if (node2edge.Used (paedge1) && node2edge.Used (paedge2)) - { - paedgenr1 = node2edge.Get (paedge1); - paedgenr2 = node2edge.Get (paedge2); - parentedges[i][0] = 2 * paedgenr1 + orient1; - parentedges[i][1] = 2 * paedgenr2 + orient2; - } - } - } - - if (parentedges[i][0] == -1) - { - // triangle split into quad+trig (from anisotropic pyramids) - for (int j = 0; j < 2; j++) - for (int k = 0; k < 2; k++) - { - INT<2> paedge (pa1[1-j], pa2[1-k]); - int orientpa = 1; - if (paedge[0] > paedge[1]) - { - Swap (paedge[0], paedge[1]); - orientpa = 0; - } - if (pa1[j] == pa2[k] && node2edge.Used(paedge)) - { - int paedgenr = node2edge.Get (paedge); - parentedges[i][0] = 2 * paedgenr + orientpa; - } - } - - } - */ + // TODO: quad edges + /* + if (parentedges[i][0] == -1) + { + // quad split + if (pa1[0] != pa2[0] && + pa1[0] != pa2[1] && + pa1[1] != pa2[0] && + pa1[1] != pa2[1]) + for (int j = 1; j <= 2; j++) + { + INT<2> paedge1, paedge2; + if (j == 1) + { + paedge1 = INT<2> (pa1[0], pa2[0]); + paedge2 = INT<2> (pa1[1], pa2[1]); + } + else + { + paedge1 = INT<2> (pa1[0], pa2[1]); + paedge2 = INT<2> (pa1[1], pa2[0]); + } - } - - } + int paedgenr1 = 0, paedgenr2 = 0; + int orient1 = 1, orient2 = 1; - /* - for (int i : Range(parent_edges)) - { - auto [info, nrs] = parent_edges[i]; - cout << "edge " << i << " has " << info << ", nrs = " << nrs[0] << " " << nrs[1] << endl; - } - */ - } + if (paedge1[0] > paedge1[1]) + { + Swap (paedge1[0], paedge1[1]); + orient1 = 0; + } + if (paedge2[0] > paedge2[1]) + { + Swap (paedge2[0], paedge2[1]); + orient2 = 0; + } + + if ( paedge1[0] == -1 || paedge2[0] == -1 ) + continue; + + if (node2edge.Used (paedge1) && node2edge.Used (paedge2)) + { + paedgenr1 = node2edge.Get (paedge1); + paedgenr2 = node2edge.Get (paedge2); + parentedges[i][0] = 2 * paedgenr1 + orient1; + parentedges[i][1] = 2 * paedgenr2 + orient2; + } + } + } + + if (parentedges[i][0] == -1) + { + // triangle split into quad+trig (from anisotropic pyramids) + for (int j = 0; j < 2; j++) + for (int k = 0; k < 2; k++) + { + INT<2> paedge (pa1[1-j], pa2[1-k]); + int orientpa = 1; + if (paedge[0] > paedge[1]) + { + Swap (paedge[0], paedge[1]); + orientpa = 0; + } + if (pa1[j] == pa2[k] && node2edge.Used(paedge)) + { + int paedgenr = node2edge.Get (paedge); + parentedges[i][0] = 2 * paedgenr + orientpa; + } + } + + } + */ + } + + } + + /* + for (int i : Range(parent_edges)) + { + auto [info, nrs] = parent_edges[i]; + cout << "edge " << i << " has " << info << ", nrs = " << nrs[0] << " " << nrs[1] << endl; + } + */ + } } From 4fad6e0631718a4bb574d67505e0ebfef1f171ce Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Thu, 1 Apr 2021 10:48:13 +0200 Subject: [PATCH 372/384] fix pickling on arm, store long type platform independent --- libsrc/core/archive.hpp | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/libsrc/core/archive.hpp b/libsrc/core/archive.hpp index 430262bf..decf8718 100644 --- a/libsrc/core/archive.hpp +++ b/libsrc/core/archive.hpp @@ -688,7 +688,11 @@ namespace ngcore Archive & operator & (short & i) override { return Write(i); } Archive & operator & (long & i) override - { return Write(i); } + { + // for platform independence + int64_t tmp = i; + return Write(tmp); + } Archive & operator & (size_t & i) override { return Write(i); } Archive & operator & (unsigned char & i) override @@ -726,14 +730,13 @@ namespace ngcore template Archive & Write (T x) { + static_assert(sizeof(T) < BUFFERSIZE, "Cannot write large types with this function!"); if (unlikely(ptr > BUFFERSIZE-sizeof(T))) { stream->write(&buffer[0], ptr); - *reinterpret_cast(&buffer[0]) = x; // NOLINT - ptr = sizeof(T); - return *this; + ptr = 0; } - *reinterpret_cast(&buffer[ptr]) = x; // NOLINT + memcpy(&buffer[ptr], &x, sizeof(T)); ptr += sizeof(T); return *this; } @@ -761,7 +764,12 @@ namespace ngcore Archive & operator & (short & i) override { Read(i); return *this; } Archive & operator & (long & i) override - { Read(i); return *this; } + { + int64_t tmp; + Read(tmp); + i = tmp; + return *this; + } Archive & operator & (size_t & i) override { Read(i); return *this; } Archive & operator & (unsigned char & i) override From daa0985a41f54678b73c4834e2bc24eab35f1246 Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Wed, 7 Apr 2021 09:58:53 +0200 Subject: [PATCH 373/384] trace memory free only when array owns memory --- libsrc/core/array.hpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/libsrc/core/array.hpp b/libsrc/core/array.hpp index 1875f38f..29f80df9 100644 --- a/libsrc/core/array.hpp +++ b/libsrc/core/array.hpp @@ -792,8 +792,9 @@ namespace ngcore /// if responsible, deletes memory NETGEN_INLINE ~Array() { + if(mem_to_delete) + mt.Free(sizeof(T)*allocsize); delete [] mem_to_delete; - mt.Free(sizeof(T)*allocsize); } // Only provide this function if T is archivable @@ -847,8 +848,9 @@ namespace ngcore /// assigns memory from local heap NETGEN_INLINE const Array & Assign (size_t asize, LocalHeap & lh) { + if(mem_to_delete) + mt.Free(sizeof(T)*allocsize); delete [] mem_to_delete; - mt.Free(sizeof(T)*allocsize); size = allocsize = asize; data = lh.Alloc (asize); mem_to_delete = nullptr; @@ -955,8 +957,9 @@ namespace ngcore /// Deallocate memory NETGEN_INLINE void DeleteAll () { + if(mem_to_delete) + mt.Free(sizeof(T)*allocsize); delete [] mem_to_delete; - mt.Free(sizeof(T)*allocsize); mem_to_delete = NULL; data = 0; size = allocsize = 0; @@ -1108,8 +1111,9 @@ namespace ngcore else for (size_t i = 0; i < mins; i++) data[i] = std::move(hdata[i]); #endif + if(mem_to_delete) + mt.Free(sizeof(T) * allocsize); delete [] mem_to_delete; - mt.Free(sizeof(T) * allocsize); } mem_to_delete = data; From d803150b87c3081814ebef11ccc03e55a292e354 Mon Sep 17 00:00:00 2001 From: Joachim Schoeberl Date: Fri, 9 Apr 2021 08:06:20 +0200 Subject: [PATCH 374/384] red refinement, parent faces (thx Guosheng) --- libsrc/meshing/topology.cpp | 42 +++++++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/libsrc/meshing/topology.cpp b/libsrc/meshing/topology.cpp index d649b23a..1a3c462e 100644 --- a/libsrc/meshing/topology.cpp +++ b/libsrc/meshing/topology.cpp @@ -1878,8 +1878,46 @@ namespace netgen } auto [info, nrs] = parent_faces[i]; - if (nrs[0] == -1) - cout << "************************** unhandled parent-face case **********************" << endl; + if (nrs[0] == -1){ + // hacking for tet red refinements + PointIndex v0 = f3[0]; + auto pa0 = mesh->mlbetweennodes[v0]; + auto pa1 = mesh->mlbetweennodes[f3[1]]; + auto pa2 = mesh->mlbetweennodes[f3[2]]; + // v0 is a coarse vertex ==> f3 is a boundary face + if (v0==pa1[0] || v0==pa1[1]){ + if (pa1[0]==v0){// type 0: bottom left corner + INT<3> parentverts(v0, pa1[1], pa2[1]); + int pafacenr = v2f[parentverts]; + parent_faces[i] = { 16, { pafacenr, -1, -1, -1} }; + //cout << "f "< parentverts(pa1[0], v0, pa2[1]); + int pafacenr = v2f[parentverts]; + parent_faces[i] = { 17, { pafacenr, -1, -1, -1} }; + //cout << "f "< parentverts(pa1[0], pa2[0], v0); + int pafacenr = v2f[parentverts]; + parent_faces[i] = { 18, { pafacenr, -1, -1, -1} }; + //cout << "f "< parentverts(pa0[0], pa0[1], pa1[1]); + int pafacenr = v2f[parentverts]; + parent_faces[i] = { 19, { pafacenr, -1, -1, -1} }; + //cout << "f "< Date: Fri, 9 Apr 2021 14:12:06 +0200 Subject: [PATCH 375/384] Find surface element of point: fix local coordinates for TRIG TRIG and TRIG6 are handled differently, see nginterface_v2.cpp:1114 --- libsrc/meshing/meshclass.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/libsrc/meshing/meshclass.cpp b/libsrc/meshing/meshclass.cpp index 4f18c139..38f614e7 100644 --- a/libsrc/meshing/meshclass.cpp +++ b/libsrc/meshing/meshclass.cpp @@ -5303,6 +5303,14 @@ namespace netgen sol.X() = lam(0); sol.Y() = lam(1); + + if (SurfaceElement(element).GetType() !=TRIG6 ) + { + sol.Z() = sol.X(); + sol.X() = sol.Y(); + sol.Y() = 1.0 - sol.Z() - sol.X(); + } + } if (sol.X() >= -eps && sol.Y() >= -eps && sol.X() + sol.Y() <= 1+eps) From 2d9e32ba70b1171043e5fd369de13a201885c709 Mon Sep 17 00:00:00 2001 From: Joachim Schoeberl Date: Fri, 9 Apr 2021 21:30:21 +0200 Subject: [PATCH 376/384] ArrayMem from BaseArray ctor --- libsrc/core/array.hpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/libsrc/core/array.hpp b/libsrc/core/array.hpp index 29f80df9..6d5fdb51 100644 --- a/libsrc/core/array.hpp +++ b/libsrc/core/array.hpp @@ -1196,6 +1196,14 @@ namespace ngcore data[cnt++] = val; } + template + ArrayMem (const BaseArrayObject & a2) + : ArrayMem (a2.Size()) + { + for (size_t i : ngcore::Range(size)) + data[i] = a2[i]; + } + ArrayMem & operator= (const T & val) { From 7c6296f153a2002e5e7f22dec979fdf447c9a3ab Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Mon, 12 Apr 2021 15:51:40 +0200 Subject: [PATCH 377/384] csg splinecurves -> shared_ptr --- libsrc/csg/csgeom.cpp | 11 +++++------ libsrc/csg/csgeom.hpp | 12 ++++++------ libsrc/csg/csgparser.cpp | 8 ++++---- libsrc/csg/extrusion.cpp | 10 +++++----- libsrc/csg/extrusion.hpp | 8 ++++---- libsrc/csg/python_csg.cpp | 7 ++++--- 6 files changed, 28 insertions(+), 28 deletions(-) diff --git a/libsrc/csg/csgeom.cpp b/libsrc/csg/csgeom.cpp index cc3e4464..e1ada634 100644 --- a/libsrc/csg/csgeom.cpp +++ b/libsrc/csg/csgeom.cpp @@ -176,9 +176,8 @@ namespace netgen solids.DeleteAll (); - for (int i = 0; i < splinecurves2d.Size(); i++) - delete splinecurves2d[i]; splinecurves2d.DeleteAll(); + splinecurves3d.DeleteAll(); /* for (int i = 0; i < surfaces.Size(); i++) @@ -712,24 +711,24 @@ namespace netgen - void CSGeometry :: SetSplineCurve (const char * name, SplineGeometry<2> * spl) + void CSGeometry :: SetSplineCurve (const char * name, shared_ptr> spl) { splinecurves2d.Set(name,spl); } - void CSGeometry :: SetSplineCurve (const char * name, SplineGeometry<3> * spl) + void CSGeometry :: SetSplineCurve (const char * name, shared_ptr> spl) { splinecurves3d.Set(name,spl); } - const SplineGeometry<2> * CSGeometry :: GetSplineCurve2d (const string & name) const + shared_ptr> CSGeometry :: GetSplineCurve2d (const string & name) const { if (splinecurves2d.Used(name)) return splinecurves2d[name]; else return NULL; } - const SplineGeometry<3> * CSGeometry :: GetSplineCurve3d (const string & name) const + shared_ptr> CSGeometry :: GetSplineCurve3d (const string & name) const { if (splinecurves3d.Used(name)) return splinecurves3d[name]; diff --git a/libsrc/csg/csgeom.hpp b/libsrc/csg/csgeom.hpp index 35453b30..17d0a3d9 100644 --- a/libsrc/csg/csgeom.hpp +++ b/libsrc/csg/csgeom.hpp @@ -115,9 +115,9 @@ namespace netgen SymbolTable solids; /// all 2d splinecurves - SymbolTable< SplineGeometry<2>* > splinecurves2d; + SymbolTable>> splinecurves2d; /// all 3d splinecurves - SymbolTable< SplineGeometry<3>* > splinecurves3d; + SymbolTable>> splinecurves3d; /// all top level objects: solids and surfaces NgArray toplevelobjects; @@ -232,10 +232,10 @@ namespace netgen const SymbolTable & GetSolids () const { return solids; } - void SetSplineCurve (const char * name, SplineGeometry<2> * spl); - void SetSplineCurve (const char * name, SplineGeometry<3> * spl); - const SplineGeometry<2> * GetSplineCurve2d (const string & name) const; - const SplineGeometry<3> * GetSplineCurve3d (const string & name) const; + void SetSplineCurve (const char * name, shared_ptr> spl); + void SetSplineCurve (const char * name, shared_ptr> spl); + shared_ptr> GetSplineCurve2d (const string & name) const; + shared_ptr> GetSplineCurve3d (const string & name) const; void DoArchive(Archive& archive) override; diff --git a/libsrc/csg/csgparser.cpp b/libsrc/csg/csgparser.cpp index 4e3c1786..05c1bdcd 100644 --- a/libsrc/csg/csgparser.cpp +++ b/libsrc/csg/csgparser.cpp @@ -511,8 +511,8 @@ namespace netgen break; } - Primitive * nprim = new Extrusion(*(geom->GetSplineCurve3d(epath)), - *(geom->GetSplineCurve2d(profile)), + Primitive * nprim = new Extrusion(geom->GetSplineCurve3d(epath), + geom->GetSplineCurve2d(profile), z_dir); geom->AddSurfaces (nprim); return new Solid(nprim); @@ -1186,7 +1186,7 @@ namespace netgen ParseChar (scan, '='); ParseChar (scan, '('); - SplineGeometry<2> * newspline = new SplineGeometry<2>; + auto newspline = make_shared>(); // newspline->CSGLoad(scan); LoadSpline (*newspline, scan); @@ -1212,7 +1212,7 @@ namespace netgen ParseChar (scan, '='); ParseChar (scan, '('); - SplineGeometry<3> * newspline = new SplineGeometry<3>; + auto newspline = make_shared>(); // newspline->CSGLoad(scan); LoadSpline (*newspline, scan); diff --git a/libsrc/csg/extrusion.cpp b/libsrc/csg/extrusion.cpp index c5518ab8..cb1466cb 100644 --- a/libsrc/csg/extrusion.cpp +++ b/libsrc/csg/extrusion.cpp @@ -658,18 +658,18 @@ namespace netgen } - Extrusion :: Extrusion(const SplineGeometry<3> & path_in, - const SplineGeometry<2> & profile_in, + Extrusion :: Extrusion(shared_ptr> path_in, + shared_ptr> profile_in, const Vec<3> & z_dir) : - path(&path_in), profile(&profile_in), z_direction(z_dir) + path(path_in), profile(profile_in), z_direction(z_dir) { surfaceactive.SetSize(0); surfaceids.SetSize(0); for(int j=0; jGetNSplines(); j++) { - ExtrusionFace * face = new ExtrusionFace(&((*profile).GetSpline(j)), - path, + ExtrusionFace * face = new ExtrusionFace(&(profile->GetSpline(j)), + path.get(), z_direction); faces.Append(face); surfaceactive.Append(true); diff --git a/libsrc/csg/extrusion.hpp b/libsrc/csg/extrusion.hpp index e9680eff..a2c8a084 100644 --- a/libsrc/csg/extrusion.hpp +++ b/libsrc/csg/extrusion.hpp @@ -121,8 +121,8 @@ namespace netgen class Extrusion : public Primitive { private: - const SplineGeometry<3>* path; - const SplineGeometry<2>* profile; // closed, clockwise oriented curve + shared_ptr> path; + shared_ptr> profile; // closed, clockwise oriented curve Vec<3> z_direction; @@ -131,8 +131,8 @@ namespace netgen mutable int latestfacenum; public: - Extrusion(const SplineGeometry<3> & path_in, - const SplineGeometry<2> & profile_in, + Extrusion(shared_ptr> path_in, + shared_ptr> profile_in, const Vec<3> & z_dir); // default constructor for archive Extrusion() {} diff --git a/libsrc/csg/python_csg.cpp b/libsrc/csg/python_csg.cpp index 0954b2d6..112c88a9 100644 --- a/libsrc/csg/python_csg.cpp +++ b/libsrc/csg/python_csg.cpp @@ -170,7 +170,8 @@ namespace netgen DLL_HEADER void ExportCSG(py::module &m) { - py::class_> (m, "SplineCurve2d") + py::class_, shared_ptr>> + (m, "SplineCurve2d") .def(py::init<>()) .def ("AddPoint", FunctionPointer ([] (SplineGeometry<2> & self, double x, double y) @@ -329,8 +330,8 @@ DLL_HEADER void ExportCSG(py::module &m) Solid * sol = new Solid(rev); return make_shared (sol); })); - m.def ("Extrusion", FunctionPointer([](const SplineGeometry<3> & path, - const SplineGeometry<2> & profile, + m.def ("Extrusion", FunctionPointer([](shared_ptr> path, + shared_ptr> profile, Vec<3> n) { Extrusion * extr = new Extrusion (path,profile,n); From 4e2d2943f66a9cdd5cafcf50c89a467cb41f25b7 Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Tue, 13 Apr 2021 12:11:10 +0200 Subject: [PATCH 378/384] fix csg extrusion --- libsrc/csg/extrusion.cpp | 2 +- libsrc/csg/python_csg.cpp | 33 +++++++++--- tests/pytest/results.json | 92 ++++++++++++++++++++++++++++++++++ tests/pytest/test_tutorials.py | 8 +-- 4 files changed, 123 insertions(+), 12 deletions(-) diff --git a/libsrc/csg/extrusion.cpp b/libsrc/csg/extrusion.cpp index cb1466cb..04efc6c0 100644 --- a/libsrc/csg/extrusion.cpp +++ b/libsrc/csg/extrusion.cpp @@ -856,7 +856,7 @@ namespace netgen return retval; if(latestfacenum >= 0) - return faces[latestfacenum]->VecInFace(p,v2,0); + return faces[latestfacenum]->VecInFace(p,v2,eps); else return VecInSolid(p,v2,eps); } diff --git a/libsrc/csg/python_csg.cpp b/libsrc/csg/python_csg.cpp index 112c88a9..a650a5ae 100644 --- a/libsrc/csg/python_csg.cpp +++ b/libsrc/csg/python_csg.cpp @@ -330,14 +330,31 @@ DLL_HEADER void ExportCSG(py::module &m) Solid * sol = new Solid(rev); return make_shared (sol); })); - m.def ("Extrusion", FunctionPointer([](shared_ptr> path, - shared_ptr> profile, - Vec<3> n) - { - Extrusion * extr = new Extrusion (path,profile,n); - Solid * sol = new Solid(extr); - return make_shared (sol); - })); + m.def ("Extrusion", [](shared_ptr> path, + shared_ptr> profile, + Vec<3> d) + { + Extrusion * extr = new Extrusion (path,profile,d); + Solid * sol = new Solid(extr); + return make_shared (sol); + }, py::arg("path"), py::arg("profile"), py::arg("d"), + R"delimiter(A body of extrusion is defined by its profile +(which has to be a closed, clockwiseoriented 2D curve), + by a path (a 3D curve) and a vector d. It is constructed + as follows: Take a point p on the path and denote the + (unit-)tangent of the path in this point by t. If we cut + the body by the plane given by p and t as normal vector, + the cut is the profile. The profile is oriented by the + (local) y-direction `y:=d−(d·t)t` and the (local) x-direction + `x:=t \times y`. +The following points have to be noticed: + * If the path is not closed, then also the body is NOT closed. + In this case e.g. planes or orthobricks have to be used to + construct a closed body. + * The path has to be smooth, i.e. the tangents at the end- resp. + start-point of two consecutive spline or line patches have to + have the same directions. +)delimiter"); m.def("EllipticCone", [](const Point<3>& a, const Vec<3>& v, const Vec<3>& w, double h, double r) { diff --git a/tests/pytest/results.json b/tests/pytest/results.json index 0ece1b09..45b04c68 100644 --- a/tests/pytest/results.json +++ b/tests/pytest/results.json @@ -1272,6 +1272,98 @@ "total_badness": 65897.969985 } ], + "extrusion.geo": [ + { + "angles_tet": [ + 6.6841, + 171.53 + ], + "angles_trig": [ + 11.293, + 152.07 + ], + "ne1d": 172, + "ne2d": 286, + "ne3d": 241, + "quality_histogram": "[0, 0, 7, 56, 39, 22, 0, 0, 0, 0, 2, 0, 5, 18, 18, 29, 21, 10, 9, 5]", + "total_badness": 775.80779693 + }, + { + "angles_tet": [ + 16.097, + 160.17 + ], + "angles_trig": [ + 15.327, + 149.09 + ], + "ne1d": 104, + "ne2d": 152, + "ne3d": 124, + "quality_histogram": "[0, 0, 0, 0, 10, 19, 39, 26, 9, 3, 1, 1, 5, 1, 3, 2, 3, 2, 0, 0]", + "total_badness": 353.53219387 + }, + { + "angles_tet": [ + 11.505, + 165.94 + ], + "angles_trig": [ + 15.054, + 147.98 + ], + "ne1d": 134, + "ne2d": 196, + "ne3d": 167, + "quality_histogram": "[0, 0, 0, 1, 3, 35, 33, 8, 5, 21, 11, 9, 10, 11, 7, 3, 5, 3, 1, 1]", + "total_badness": 417.63980201 + }, + { + "angles_tet": [ + 6.6841, + 171.53 + ], + "angles_trig": [ + 11.293, + 152.07 + ], + "ne1d": 172, + "ne2d": 286, + "ne3d": 241, + "quality_histogram": "[0, 0, 7, 56, 39, 22, 0, 0, 0, 0, 2, 0, 5, 18, 18, 29, 21, 10, 9, 5]", + "total_badness": 775.80779693 + }, + { + "angles_tet": [ + 17.691, + 140.88 + ], + "angles_trig": [ + 18.812, + 116.06 + ], + "ne1d": 276, + "ne2d": 570, + "ne3d": 646, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 4, 17, 30, 51, 51, 55, 81, 69, 74, 73, 72, 52, 12, 5]", + "total_badness": 1020.0235117 + }, + { + "angles_tet": [ + 14.402, + 155.5 + ], + "angles_trig": [ + 24.071, + 119.03 + ], + "ne1d": 442, + "ne2d": 1220, + "ne3d": 2802, + "quality_histogram": "[0, 0, 0, 0, 0, 2, 5, 2, 4, 12, 25, 55, 147, 298, 311, 503, 457, 536, 342, 103]", + "total_badness": 3603.431162 + } + ], "fichera.geo": [ { "angles_tet": [ diff --git a/tests/pytest/test_tutorials.py b/tests/pytest/test_tutorials.py index 90bccc3f..b3cf7704 100644 --- a/tests/pytest/test_tutorials.py +++ b/tests/pytest/test_tutorials.py @@ -63,8 +63,6 @@ def getMeshingparameters(filename): standard = [MeshingParameters()] + [MeshingParameters(ms) for ms in (meshsize.very_coarse, meshsize.coarse, meshsize.moderate, meshsize.fine, meshsize.very_fine)] if filename == "shell.geo": return [] # do not test this example cause it needs so long... - if filename == "extrusion.geo": - return [] # this segfaults right now if filename == "manyholes2.geo": return [standard[1]] # this gets too big for finer meshsizes if filename in ("manyholes.geo", "frame.step"): @@ -142,7 +140,11 @@ def generateResultFile(): continue meshdata = [] for mp in mps: - mesh = generateMesh(_file, mp) + try: + mesh = generateMesh(_file, mp) + except Exception as e: + print("Meshingparameters: ", mp) + raise e meshdata.append( getData(mesh, mp) ) data[_file] = meshdata print("needed", time.time() - start, "seconds") From 6e87ff6ea7e0302bc0c58fffcd629195a26e8948 Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Thu, 15 Apr 2021 19:02:05 +0200 Subject: [PATCH 379/384] allow spirals with extrusion using zones --- libsrc/csg/extrusion.cpp | 31 ++++++++++++++++++++++++++++++- libsrc/csg/extrusion.hpp | 7 +++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/libsrc/csg/extrusion.cpp b/libsrc/csg/extrusion.cpp index 04efc6c0..9fd2c39d 100644 --- a/libsrc/csg/extrusion.cpp +++ b/libsrc/csg/extrusion.cpp @@ -41,6 +41,16 @@ namespace netgen loc_z_dir[i] = glob_z_direction; } } + + for(auto i : Range(path->GetSplines())) + { + const auto& sp = path->GetSpline(i); + auto t1 = sp.GetTangent(0.); + t1.Normalize(); + auto t2 = sp.GetTangent(1.); + t2.Normalize(); + angles.Append(acos(t1 * t2)); + } profile->GetCoeff(profile_spline_coeff); latest_point3d = -1.111e30; @@ -656,7 +666,26 @@ namespace netgen dez /= lenz; dez -= (dez * ez) * ez; } - + + void ExtrusionFace :: DefineTangentialPlane(const Point<3>& ap1, + const Point<3>& ap2) + { + Surface::DefineTangentialPlane(ap1, ap2); + tangential_plane_seg = latest_seg; + } + + void ExtrusionFace :: ToPlane(const Point<3>& p3d, Point<2>& p2d, + double h, int& zone) const + { + Surface::ToPlane(p3d, p2d, h, zone); + double angle = 0; + for(int i = latest_seg; i < tangential_plane_seg; i++) + angle += angles[i]; + for(int i = tangential_plane_seg; i < latest_seg; i++) + angle -= angles[i]; + if(fabs(angle) > 3.14/2.) + zone = -1; + } Extrusion :: Extrusion(shared_ptr> path_in, shared_ptr> profile_in, diff --git a/libsrc/csg/extrusion.hpp b/libsrc/csg/extrusion.hpp index a2c8a084..af951c51 100644 --- a/libsrc/csg/extrusion.hpp +++ b/libsrc/csg/extrusion.hpp @@ -12,8 +12,10 @@ namespace netgen const SplineSeg<2> * profile; const SplineGeometry<3> * path; Vec<3> glob_z_direction; + Array angles; bool deletable; + int tangential_plane_seg; NgArray< const SplineSeg3<3> * > spline3_path; NgArray< const LineSeg<3> * > line_path; @@ -114,6 +116,11 @@ namespace netgen Vec<3> & ex, Vec<3> & ey, Vec<3> & ez, Vec<3> & dex, Vec<3> & dey, Vec<3> & dez) const; + void DefineTangentialPlane(const Point<3>& ap1, + const Point<3>& ap2) override; + void ToPlane(const Point<3>& p3d, Point<2>& p2d, + double h, int& zone) const override; + }; From 21ef833bbd21a3a243e237632901fdabafb5c791 Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Thu, 15 Apr 2021 19:31:36 +0200 Subject: [PATCH 380/384] very fine extrusion has problems in tests... --- tests/pytest/test_tutorials.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/pytest/test_tutorials.py b/tests/pytest/test_tutorials.py index b3cf7704..236749da 100644 --- a/tests/pytest/test_tutorials.py +++ b/tests/pytest/test_tutorials.py @@ -67,6 +67,8 @@ def getMeshingparameters(filename): return [standard[1]] # this gets too big for finer meshsizes if filename in ("manyholes.geo", "frame.step"): return standard[:3] # this gets too big for finer meshsizes + if filename == "extrusion.geo": + return standard[:-1] if filename == "screw.step": return standard[3:] # coarser meshes don't work here if filename == "cylsphere.geo": From 087a830a67be54dd34d177649b6c6b3697a68832 Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Thu, 15 Apr 2021 22:48:16 +0200 Subject: [PATCH 381/384] store cumulated angle --- libsrc/csg/extrusion.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/libsrc/csg/extrusion.cpp b/libsrc/csg/extrusion.cpp index 9fd2c39d..82b2e651 100644 --- a/libsrc/csg/extrusion.cpp +++ b/libsrc/csg/extrusion.cpp @@ -42,6 +42,7 @@ namespace netgen } } + double cum_angle = 0.; for(auto i : Range(path->GetSplines())) { const auto& sp = path->GetSpline(i); @@ -49,7 +50,8 @@ namespace netgen t1.Normalize(); auto t2 = sp.GetTangent(1.); t2.Normalize(); - angles.Append(acos(t1 * t2)); + cum_angle += acos(t1 * t2); + angles.Append(cum_angle); } profile->GetCoeff(profile_spline_coeff); @@ -678,11 +680,7 @@ namespace netgen double h, int& zone) const { Surface::ToPlane(p3d, p2d, h, zone); - double angle = 0; - for(int i = latest_seg; i < tangential_plane_seg; i++) - angle += angles[i]; - for(int i = tangential_plane_seg; i < latest_seg; i++) - angle -= angles[i]; + double angle = angles[tangential_plane_seg] - angles[latest_seg]; if(fabs(angle) > 3.14/2.) zone = -1; } From 0763e4a5d1f2afb257a9b231ee02b7499593c4eb Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Sat, 17 Apr 2021 16:27:30 +0200 Subject: [PATCH 382/384] fix override warnings --- libsrc/csg/extrusion.hpp | 61 ++++++++++++++++++++-------------------- 1 file changed, 30 insertions(+), 31 deletions(-) diff --git a/libsrc/csg/extrusion.hpp b/libsrc/csg/extrusion.hpp index af951c51..e29d5660 100644 --- a/libsrc/csg/extrusion.hpp +++ b/libsrc/csg/extrusion.hpp @@ -56,7 +56,7 @@ namespace netgen ~ExtrusionFace(); - virtual void DoArchive(Archive& ar) + void DoArchive(Archive& ar) override { Surface::DoArchive(ar); ar & profile & path & glob_z_direction & deletable & spline3_path & line_path & @@ -64,25 +64,25 @@ namespace netgen profile_spline_coeff & latest_seg & latest_t & latest_point2d & latest_point3d; } - virtual int IsIdentic (const Surface & s2, int & inv, double eps) const; + int IsIdentic (const Surface & s2, int & inv, double eps) const override; - virtual double CalcFunctionValue (const Point<3> & point) const; - virtual void CalcGradient (const Point<3> & point, Vec<3> & grad) const; - virtual void CalcHesse (const Point<3> & point, Mat<3> & hesse) const; - virtual double HesseNorm () const; + double CalcFunctionValue (const Point<3> & point) const override; + void CalcGradient (const Point<3> & point, Vec<3> & grad) const override; + void CalcHesse (const Point<3> & point, Mat<3> & hesse) const override; + double HesseNorm () const override; - virtual double MaxCurvature () const; + double MaxCurvature () const override; //virtual double MaxCurvatureLoc (const Point<3> & /* c */ , // double /* rad */) const; - virtual void Project (Point<3> & p) const; + void Project (Point<3> & p) const override; - virtual Point<3> GetSurfacePoint () const; - virtual void Print (ostream & str) const; + Point<3> GetSurfacePoint () const override; + void Print (ostream & str) const override; - virtual void GetTriangleApproximation (TriangleApproximation & tas, + void GetTriangleApproximation (TriangleApproximation & tas, const Box<3> & boundingbox, - double facets) const; + double facets) const override; const SplineGeometry<3> & GetPath(void) const {return *path;} const SplineSeg<2> & GetProfile(void) const {return *profile;} @@ -145,40 +145,39 @@ namespace netgen Extrusion() {} ~Extrusion(); - virtual void DoArchive(Archive& ar) + void DoArchive(Archive& ar) override { Primitive::DoArchive(ar); ar & path & profile & z_direction & faces & latestfacenum; } - virtual INSOLID_TYPE BoxInSolid (const BoxSphere<3> & box) const; - virtual INSOLID_TYPE PointInSolid (const Point<3> & p, - double eps) const; + INSOLID_TYPE BoxInSolid (const BoxSphere<3> & box) const override; + INSOLID_TYPE PointInSolid (const Point<3> & p, + double eps) const override; INSOLID_TYPE PointInSolid (const Point<3> & p, double eps, NgArray * const facenums) const; - virtual void GetTangentialSurfaceIndices (const Point<3> & p, - NgArray & surfind, double eps) const; + void GetTangentialSurfaceIndices (const Point<3> & p, + NgArray & surfind, double eps) const override; - virtual INSOLID_TYPE VecInSolid (const Point<3> & p, - const Vec<3> & v, - double eps) const; + INSOLID_TYPE VecInSolid (const Point<3> & p, + const Vec<3> & v, + double eps) const override; // checks if lim s->0 lim t->0 p + t(v1 + s v2) in solid - virtual INSOLID_TYPE VecInSolid2 (const Point<3> & p, - const Vec<3> & v1, - const Vec<3> & v2, - double eps) const; + INSOLID_TYPE VecInSolid2 (const Point<3> & p, + const Vec<3> & v1, + const Vec<3> & v2, + double eps) const override; - virtual int GetNSurfaces() const; - virtual Surface & GetSurface (int i = 0); - virtual const Surface & GetSurface (int i = 0) const; + int GetNSurfaces() const override; + Surface & GetSurface (int i = 0) override; + const Surface & GetSurface (int i = 0) const override; - virtual void Reduce (const BoxSphere<3> & box); - virtual void UnReduce (); - + void Reduce (const BoxSphere<3> & box) override; + void UnReduce () override; }; } From 9033de843bb360416ef7526908575bcdcf156a74 Mon Sep 17 00:00:00 2001 From: Joachim Schoeberl Date: Sun, 18 Apr 2021 17:53:16 +0200 Subject: [PATCH 383/384] uniform refinement for quads --- libsrc/meshing/refine.cpp | 116 ++++++++++++++++++++++++-------------- 1 file changed, 74 insertions(+), 42 deletions(-) diff --git a/libsrc/meshing/refine.cpp b/libsrc/meshing/refine.cpp index b9d06c16..d8d49870 100644 --- a/libsrc/meshing/refine.cpp +++ b/libsrc/meshing/refine.cpp @@ -77,6 +77,32 @@ namespace netgen } break; } + case QUAD: + { + static int betw[5][3] = + { { 0, 1, 4 }, + { 1, 2, 5 }, + { 2, 3, 6 }, + { 0, 3, 7 }, + { 0, 2, 8 } }; // one diagonal of the quad. should change later to mid-point of edge mid-points + for (int j = 0; j < 5; j++) + { + auto i2 = PointIndices<2>::Sort(el[betw[j][0]],el[betw[j][1]]); + if (j == 4) + { + auto i2a = PointIndices<2>::Sort(el[0], el[2]); + auto i2b = PointIndices<2>::Sort(el[1], el[3]); + i2 = i2a[0] < i2b[0] ? i2a : i2b; + } + if (!between.Used(i2)) + { + between.Set (i2, 0); + parents.Append(i2); + } + } + break; + } + default: throw NgException ("currently refinement for quad-elements is not supported"); } @@ -125,7 +151,7 @@ namespace netgen between.Set (parents[i], mesh.GetNV()+i+PointIndex::BASE); mesh.mlbetweennodes[mesh.GetNV()+i+PointIndex::BASE] = parents[i]; } - + mesh.SetNP(mesh.GetNV() + parents.Size()); NgArray pointset(mesh.GetNP()); pointset = false; @@ -281,70 +307,76 @@ namespace netgen case QUAD6: case QUAD8: { - NgArrayMem pnums(9); - NgArrayMem pgis(9); + PointIndex pnums[9]; + PointGeomInfo pgis[9]; static int betw[5][3] = - { { 1, 2, 5 }, + { { 0, 1, 4 }, + { 1, 2, 5 }, { 2, 3, 6 }, - { 3, 4, 7 }, - { 1, 4, 8 }, - { 5, 7, 9 } }; - - for (int j = 1; j <= 4; j++) + { 0, 3, 7 }, + { 0, 2, 8 } }; + + for (int j = 0; j < 4; j++) { - pnums.Elem(j) = el.PNum(j); - pgis.Elem(j) = el.GeomInfoPi(j); + pnums[j] = el[j]; + pgis[j] = el.GeomInfoPi(j+1); } for (int j = 0; j < 5; j++) { - int pi1 = pnums.Elem(betw[j][0]); - int pi2 = pnums.Elem(betw[j][1]); + int pi1 = pnums[betw[j][0]]; + int pi2 = pnums[betw[j][1]]; INDEX_2 i2 (pi1, pi2); i2.Sort(); + + if (j == 4) + { + auto i2a = PointIndices<2>::Sort(el[0], el[2]); + auto i2b = PointIndices<2>::Sort(el[1], el[3]); + i2 = i2a[0] < i2b[0] ? i2a : i2b; + } - if (between.Used(i2)) - { - pnums.Elem(5+j) = between.Get(i2); - pgis.Elem(5+j) = surfgi.Get(pnums.Elem(4+j)); - } - else - { - Point<3> pb; - geo.PointBetween(mesh.Point (pi1), - mesh.Point (pi2), 0.5, - mesh.GetFaceDescriptor(el.GetIndex ()).SurfNr(), - el.GeomInfoPi (betw[j][0]), - el.GeomInfoPi (betw[j][1]), - pb, pgis.Elem(5+j)); + Point<3> pb; + PointGeomInfo pgi; + geo.PointBetween(mesh.Point (pi1), mesh.Point (pi2), 0.5, + mesh.GetFaceDescriptor(el.GetIndex ()).SurfNr(), + el.GeomInfoPi (betw[j][0]+1 ), + el.GeomInfoPi (betw[j][1]+1 ), + pb, pgi); - pnums.Elem(5+j) = mesh.AddPoint (pb); + pgis[4+j] = pgi; + PointIndex pinew = between.Get(i2); + pnums[4+j] = pinew; - between.Set (i2, pnums.Get(5+j)); - - if (surfgi.Size() < pnums.Elem(5+j)) - surfgi.SetSize (pnums.Elem(5+j)); - surfgi.Elem(pnums.Elem(5+j)) = pgis.Elem(5+j); - } - } + if (!pointset[pinew]) + { + pointset[pinew] = true; + mesh.Point(pinew) = pb; + } + + if (surfgi.Size() < pnums[4+j]) + surfgi.SetSize (pnums[4+j]); + surfgi.Elem(pnums[4+j]) = pgis[4+j]; + } static int reftab[4][4] = { - { 1, 5, 9, 8 }, - { 5, 2, 6, 9 }, - { 8, 9, 7, 4 }, - { 9, 6, 3, 7 } }; + { 0, 4, 8, 7 }, + { 4, 1, 5, 8 }, + { 7, 8, 6, 3 }, + { 8, 5, 2, 6 } }; + int ind = el.GetIndex(); for (int j = 0; j < 4; j++) { Element2d nel(QUAD); - for (int k = 1; k <= 4; k++) + for (int k = 0; k < 4; k++) { - nel.PNum(k) = pnums.Get(reftab[j][k-1]); - nel.GeomInfoPi(k) = pgis.Get(reftab[j][k-1]); + nel[k] = pnums[reftab[j][k]]; + nel.GeomInfoPi(k+1) = pgis[reftab[j][k]]; } nel.SetIndex(ind); From acf2b39680257539be054b863f0a1951b527a4fc Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Fri, 23 Apr 2021 20:06:48 +0200 Subject: [PATCH 384/384] Fix cross-platform archiving This is a non-backward compatible change for archives on Windows! --- libsrc/core/utils.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/libsrc/core/utils.cpp b/libsrc/core/utils.cpp index bf355bc1..cfa3fef8 100644 --- a/libsrc/core/utils.cpp +++ b/libsrc/core/utils.cpp @@ -13,7 +13,15 @@ namespace ngcore #ifdef WIN32 // windows does demangling in typeid(T).name() - NGCORE_API std::string Demangle(const char* typeinfo) { return typeinfo; } + NGCORE_API std::string Demangle(const char* typeinfo) { + std::string name = typeinfo; + // remove "class " and "struct " at beginning of type names to be consistent with demangled names of gcc/clang + if(name.find("class ") == 0) + name.erase(0,6); + if(name.find("struct ") == 0) + name.erase(0,7); + return name; + } #else NGCORE_API std::string Demangle(const char* typeinfo) {