From f95332d0a1ad8bdd8be5101ef716f52a0ee42e26 Mon Sep 17 00:00:00 2001 From: "mhochsteger@cerbsim.com" Date: Wed, 10 Nov 2021 12:08:56 +0100 Subject: [PATCH 1/7] archive optional --- libsrc/core/archive.hpp | 19 +++++++++++++++++++ tests/catch/archive.cpp | 26 ++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/libsrc/core/archive.hpp b/libsrc/core/archive.hpp index 0e5d69bc..4d72e826 100644 --- a/libsrc/core/archive.hpp +++ b/libsrc/core/archive.hpp @@ -9,6 +9,7 @@ #include // for function #include // for map #include // for shared_ptr +#include // for optional #include // for string #include // for declval, enable_if_t, false_type, is_co... #include // for std::byte @@ -290,6 +291,24 @@ namespace ngcore } return (*this); } + template + Archive& operator& (std::optional& opt) + { + bool has_value = opt.has_value(); + (*this) & has_value; + if(has_value) + { + if(Output()) + (*this) << *opt; + else + { + T value; + (*this) & value; + opt = value; + } + } + return (*this); + } // Archive arrays ===================================================== // this functions can be overloaded in Archive implementations for more efficiency template >> diff --git a/tests/catch/archive.cpp b/tests/catch/archive.cpp index 8d7a413c..8c436697 100644 --- a/tests/catch/archive.cpp +++ b/tests/catch/archive.cpp @@ -265,6 +265,28 @@ void testEnum(Archive& in, Archive& out) CHECK(enin == CASE2); } +void testOptional(Archive& in, Archive& out) + { + { + std::optional no_value; + std::optional myint = 42; + std::optional mystr = "have an optional string"; + out & no_value & myint & mystr; + out.FlushBuffer(); + } + { + std::optional no_value_; + std::optional myint_; + std::optional mystr_; + in & no_value_ & myint_ & mystr_; + CHECK(no_value_.has_value() == false); + CHECK(myint_.has_value() == true); + CHECK(*myint_ == 42); + CHECK(mystr_.has_value() == true); + CHECK(*mystr_ == "have an optional string"); + } + } + void testArchive(Archive& in, Archive& out) { SECTION("Empty String") @@ -322,6 +344,10 @@ void testArchive(Archive& in, Archive& out) { testEnum(in, out); } + SECTION("optional") + { + testOptional(in, out); + } } TEST_CASE("BinaryArchive") From b63baa57be7fee3a45164c72693cd13db355e717 Mon Sep 17 00:00:00 2001 From: "mhochsteger@cerbsim.com" Date: Wed, 10 Nov 2021 12:09:52 +0100 Subject: [PATCH 2/7] ShapeProperties::DoArchive() --- libsrc/occ/occgeom.hpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/libsrc/occ/occgeom.hpp b/libsrc/occ/occgeom.hpp index af61bd1f..59e5245c 100644 --- a/libsrc/occ/occgeom.hpp +++ b/libsrc/occ/occgeom.hpp @@ -232,6 +232,11 @@ namespace netgen if (prop2.col) col = prop2.col; maxh = min2(maxh, prop2.maxh); } + + void DoArchive(Archive& ar) + { + ar & name & col & maxh & hpref; + } }; From 4d7ef21791ea60a98bde3374b576e7a19d017762 Mon Sep 17 00:00:00 2001 From: "mhochsteger@cerbsim.com" Date: Wed, 10 Nov 2021 18:16:25 +0100 Subject: [PATCH 3/7] proper DoArchive for OCCGeometry --- libsrc/occ/occgeom.cpp | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/libsrc/occ/occgeom.cpp b/libsrc/occ/occgeom.cpp index 2ca0c746..c70019a2 100644 --- a/libsrc/occ/occgeom.cpp +++ b/libsrc/occ/occgeom.cpp @@ -1659,26 +1659,28 @@ namespace netgen if(ar.Output()) { std::stringstream ss; - STEPControl_Writer writer; - writer.Transfer(shape, STEPControl_AsIs); - auto filename = GetTempFilename(); - writer.Write(filename.c_str()); - std::ifstream is(filename.c_str()); - ss << is.rdbuf(); + BRepTools::Write(shape, ss); ar << ss.str(); - std::remove(filename.c_str()); } else { std::string str; ar & str; + stringstream ss(str); + BRep_Builder builder; + BRepTools::Read(shape, ss, builder); + } - auto filename = GetTempFilename(); - auto tmpfile = std::fopen(filename.c_str(), "w"); - std::fputs(str.c_str(), tmpfile); - std::fclose(tmpfile); - LoadOCCInto(this, filename.c_str()); - std::remove(filename.c_str()); + ar & occdim; + for (auto typ : { TopAbs_SOLID, TopAbs_FACE, TopAbs_EDGE }) + for (TopExp_Explorer e(shape, typ); e.More(); e.Next()) + ar & global_shape_properties[e.Current().TShape()]; + + if(ar.Input()) + { + changed = 1; + BuildFMap(); + CalcBoundingBox(); } } From 17458889aaec2e909549876ea0d0885d399d8b1d Mon Sep 17 00:00:00 2001 From: "mhochsteger@cerbsim.com" Date: Wed, 10 Nov 2021 12:13:04 +0100 Subject: [PATCH 4/7] Change interface of LoadFromMeshFile Fetch the first (geometry identification) token only once (and not on each try to load a different type) --- libsrc/csg/csgeom.cpp | 24 ++++++++---------------- libsrc/interface/nginterface.cpp | 11 ++--------- libsrc/meshing/basegeom.cpp | 2 +- libsrc/meshing/basegeom.hpp | 2 +- ng/ngpkg.cpp | 14 ++++---------- 5 files changed, 16 insertions(+), 37 deletions(-) diff --git a/libsrc/csg/csgeom.cpp b/libsrc/csg/csgeom.cpp index 511eb4bf..663b60d1 100644 --- a/libsrc/csg/csgeom.cpp +++ b/libsrc/csg/csgeom.cpp @@ -1620,7 +1620,7 @@ namespace netgen { public: virtual NetgenGeometry * Load (string filename) const; - virtual NetgenGeometry * LoadFromMeshFile (istream & ist) const; + virtual NetgenGeometry * LoadFromMeshFile (istream & ist, string token) const; // virtual VisualScene * GetVisualScene (const NetgenGeometry * geom) const; }; @@ -1659,22 +1659,14 @@ namespace netgen return NULL; } - NetgenGeometry * CSGeometryRegister :: LoadFromMeshFile (istream & ist) const + NetgenGeometry * CSGeometryRegister :: LoadFromMeshFile (istream & ist, string token) const { - string auxstring; - if (ist.good()) - { - ist >> auxstring; - if (auxstring == "csgsurfaces") - { - CSGeometry * geometry = new CSGeometry (""); - geometry -> LoadSurfaces(ist); - return geometry; - } - // else - // ist.putback (auxstring); - } - return NULL; + if (token != "csgsurfaces") + return nullptr; + + CSGeometry * geometry = new CSGeometry (""); + geometry -> LoadSurfaces(ist); + return geometry; } diff --git a/libsrc/interface/nginterface.cpp b/libsrc/interface/nginterface.cpp index c564e5e2..a1c75ac7 100644 --- a/libsrc/interface/nginterface.cpp +++ b/libsrc/interface/nginterface.cpp @@ -104,15 +104,8 @@ void Ng_LoadMeshFromStream ( istream & input ) mesh -> Load(input); SetGlobalMesh (mesh); - for (int i = 0; i < geometryregister.Size(); i++) - { - NetgenGeometry * hgeom = geometryregister[i]->LoadFromMeshFile (input); - if (hgeom) - { - ng_geometry.reset (hgeom); - break; - } - } + ng_geometry = geometryregister.LoadFromMeshFile (input); + if (!ng_geometry) ng_geometry = make_shared(); mesh->SetGeometry (ng_geometry); diff --git a/libsrc/meshing/basegeom.cpp b/libsrc/meshing/basegeom.cpp index 8ae67dc8..40e45fc1 100644 --- a/libsrc/meshing/basegeom.cpp +++ b/libsrc/meshing/basegeom.cpp @@ -509,7 +509,7 @@ namespace netgen { for (int i = 0; i < Size(); i++) { - NetgenGeometry * hgeom = (*this)[i]->LoadFromMeshFile (ist); + NetgenGeometry * hgeom = (*this)[i]->LoadFromMeshFile (ist, token); if (hgeom) return shared_ptr(hgeom); } diff --git a/libsrc/meshing/basegeom.hpp b/libsrc/meshing/basegeom.hpp index f7ed62ab..8d367966 100644 --- a/libsrc/meshing/basegeom.hpp +++ b/libsrc/meshing/basegeom.hpp @@ -224,7 +224,7 @@ namespace netgen public: virtual ~GeometryRegister(); virtual NetgenGeometry * Load (string filename) const = 0; - virtual NetgenGeometry * LoadFromMeshFile (istream & /* ist */) const { return NULL; } + virtual NetgenGeometry * LoadFromMeshFile (istream & /* ist */, string) const { return NULL; } virtual class VisualScene * GetVisualScene (const NetgenGeometry * /* geom */) const { return NULL; } virtual void SetParameters (Tcl_Interp * /* interp */) { ; } diff --git a/ng/ngpkg.cpp b/ng/ngpkg.cpp index 38a22514..ab950d79 100644 --- a/ng/ngpkg.cpp +++ b/ng/ngpkg.cpp @@ -233,16 +233,10 @@ namespace netgen MyMPI_SendCmd ("mesh"); mesh -> Distribute(); #endif - for (int i = 0; i < geometryregister.Size(); i++) - { - NetgenGeometry * hgeom = geometryregister[i]->LoadFromMeshFile (*infile); - if (hgeom) - { - ng_geometry = shared_ptr(hgeom); - break; - } - } - delete infile; + auto geo = geometryregister.LoadFromMeshFile (*infile); + if(geo) + ng_geometry = geo; + delete infile; /* string auxstring; From e0afa0a91610cac1bad99e37ab1b42506e288141 Mon Sep 17 00:00:00 2001 From: "mhochsteger@cerbsim.com" Date: Wed, 10 Nov 2021 18:19:18 +0100 Subject: [PATCH 5/7] Use TextOutArchive to store OCCGeometry in mesh files --- libsrc/meshing/basegeom.cpp | 18 ++++++++++++++++++ libsrc/occ/occgeom.cpp | 12 ++++++++++++ libsrc/occ/occgeom.hpp | 1 + 3 files changed, 31 insertions(+) diff --git a/libsrc/meshing/basegeom.cpp b/libsrc/meshing/basegeom.cpp index 40e45fc1..62c0b981 100644 --- a/libsrc/meshing/basegeom.cpp +++ b/libsrc/meshing/basegeom.cpp @@ -507,6 +507,24 @@ namespace netgen shared_ptr GeometryRegisterArray :: LoadFromMeshFile (istream & ist) const { + if (!ist.good()) + return nullptr; + + string token; + ist >> token; + if(token == "TextOutArchive") + { + NetgenGeometry *geo = nullptr; + size_t string_length; + ist >> string_length; + string buffer(string_length+1, '\0'); + ist.read(&buffer[0], string_length); + auto ss = make_shared(buffer); + TextInArchive in(ss); + in & geo; + + return shared_ptr(geo); + } for (int i = 0; i < Size(); i++) { NetgenGeometry * hgeom = (*this)[i]->LoadFromMeshFile (ist, token); diff --git a/libsrc/occ/occgeom.cpp b/libsrc/occ/occgeom.cpp index c70019a2..734044b4 100644 --- a/libsrc/occ/occgeom.cpp +++ b/libsrc/occ/occgeom.cpp @@ -1654,6 +1654,18 @@ namespace netgen } } + void OCCGeometry :: SaveToMeshFile (ostream & ost) const + { + auto ss = make_shared(); + TextOutArchive out(ss); + NetgenGeometry *geo = const_cast(this); + out & geo; + + ost << "TextOutArchive" << endl; + ost << ss->str().size() << endl; + ost << ss->str(); + } + void OCCGeometry :: DoArchive(Archive& ar) { if(ar.Output()) diff --git a/libsrc/occ/occgeom.hpp b/libsrc/occ/occgeom.hpp index 59e5245c..381a3df1 100644 --- a/libsrc/occ/occgeom.hpp +++ b/libsrc/occ/occgeom.hpp @@ -380,6 +380,7 @@ namespace netgen void FinalizeMesh(Mesh& mesh) const override; void Save (string filename) const override; + void SaveToMeshFile (ostream & /* ost */) const override; void DoArchive(Archive& ar) override; From 36f22a13ced27ac6a9fcf13a0172d1369fe9601b Mon Sep 17 00:00:00 2001 From: "mhochsteger@cerbsim.com" Date: Thu, 11 Nov 2021 12:44:34 +0100 Subject: [PATCH 6/7] also save occ identifications in mesh file attachment --- libsrc/gprim/geomobjects.hpp | 5 ++++ libsrc/gprim/transform3d.hpp | 5 ++++ libsrc/occ/occgeom.cpp | 56 +++++++++++++++++++++++++++++++++++- 3 files changed, 65 insertions(+), 1 deletion(-) diff --git a/libsrc/gprim/geomobjects.hpp b/libsrc/gprim/geomobjects.hpp index 5cfc2eb9..32a22318 100644 --- a/libsrc/gprim/geomobjects.hpp +++ b/libsrc/gprim/geomobjects.hpp @@ -269,6 +269,11 @@ namespace netgen CalcInverse (*this, inv); sol = inv * rhs; } + + void DoArchive(Archive & ar) + { + ar.Do(x, H*W); + } }; diff --git a/libsrc/gprim/transform3d.hpp b/libsrc/gprim/transform3d.hpp index c61a9a99..b5886d29 100644 --- a/libsrc/gprim/transform3d.hpp +++ b/libsrc/gprim/transform3d.hpp @@ -133,6 +133,11 @@ public: Mat & GetMatrix() { return m; } Vec & GetVector() { return v; } + void DoArchive(Archive& ar) + { + ar & m & v; + } + /// Transformation CalcInverse () const { diff --git a/libsrc/occ/occgeom.cpp b/libsrc/occ/occgeom.cpp index 734044b4..a097ce31 100644 --- a/libsrc/occ/occgeom.cpp +++ b/libsrc/occ/occgeom.cpp @@ -1668,6 +1668,8 @@ namespace netgen void OCCGeometry :: DoArchive(Archive& ar) { + int version = 0; + ar & version; if(ar.Output()) { std::stringstream ss; @@ -1683,10 +1685,62 @@ namespace netgen BRepTools::Read(shape, ss, builder); } + // enumerate shapes and archive only integers + auto my_hash = [](const TopoDS_Shape & key) { + auto occ_hash = key.HashCode(1<<31UL); + return std::hash()(occ_hash); + }; + std::unordered_map shape_map(10, my_hash); + Array shape_list; + + std::map tshape_map; + Array tshape_list; + ar & occdim; for (auto typ : { TopAbs_SOLID, TopAbs_FACE, TopAbs_EDGE }) for (TopExp_Explorer e(shape, typ); e.More(); e.Next()) - ar & global_shape_properties[e.Current().TShape()]; + { + auto ds = e.Current(); + auto ts = ds.TShape(); + if(shape_map.count(ds)==0) + { + shape_map[ds] = shape_list.Size(); + shape_list.Append(ds); + } + if(tshape_map.count(ts)==0) + { + tshape_map[ts] = shape_list.Size(); + tshape_list.Append(ts); + } + } + + for (auto ts : tshape_list) + { + bool has_properties = global_shape_properties.count(ts); + ar & has_properties; + if(has_properties) + ar & global_shape_properties[ts]; + + bool has_identifications = identifications.count(ts); + ar & has_identifications; + if(has_identifications) + { + auto & idents = identifications[ts]; + auto n_idents = idents.size(); + ar & n_idents; + idents.resize(n_idents); + for(auto i : Range(n_idents)) + { + auto & id = idents[i]; + int shape_id; + if(ar.Output()) + shape_id = shape_map[id.other]; + ar & shape_id & id.trafo & id.inverse & id.name; + if(ar.Input()) + id.other = shape_list[shape_id]; + } + } + } if(ar.Input()) { From 8c9cdfbc345881d297f4705bb0fc21885ba45c09 Mon Sep 17 00:00:00 2001 From: "mhochsteger@cerbsim.com" Date: Thu, 11 Nov 2021 15:25:12 +0100 Subject: [PATCH 7/7] store netgen version, introduce "format_version" for future changes --- libsrc/occ/occgeom.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/libsrc/occ/occgeom.cpp b/libsrc/occ/occgeom.cpp index a097ce31..d5a85e97 100644 --- a/libsrc/occ/occgeom.cpp +++ b/libsrc/occ/occgeom.cpp @@ -1668,8 +1668,12 @@ namespace netgen void OCCGeometry :: DoArchive(Archive& ar) { - int version = 0; - ar & version; + constexpr int current_format_version = 0; + + int format_version = current_format_version; + auto netgen_version = GetLibraryVersion("netgen"); + ar & netgen_version & format_version; + if(ar.Output()) { std::stringstream ss; @@ -1678,6 +1682,11 @@ namespace netgen } else { + if(format_version>current_format_version) + throw Exception("Loading OCCGeometry from archive: unkown format version " + + ToString(format_version) + + ", written by netgen version " + + ToString(netgen_version)); std::string str; ar & str; stringstream ss(str);