Use webgui for debugging

This commit is contained in:
Matthias Hochsteger 2024-03-22 15:44:24 +01:00
parent e5513d9417
commit 5be5567f79
5 changed files with 268 additions and 95 deletions

View File

@ -8,6 +8,7 @@
/**************************************************************************/ /**************************************************************************/
#include <core/array.hpp> #include <core/array.hpp>
#include <ostream>
namespace netgen namespace netgen
{ {
@ -218,11 +219,11 @@ namespace netgen
// print array // print array
template <typename T, int BASE, typename TIND> template <typename T, int BASE, typename TIND>
inline ostream & operator<< (ostream & s, const NgFlatArray<T,BASE,TIND> & a) inline std::ostream & operator<< (std::ostream & s, const NgFlatArray<T,BASE,TIND> & a)
{ {
// for (TIND i = a.Begin(); i < a.End(); i++) // for (TIND i = a.Begin(); i < a.End(); i++)
for (auto i : a.Range()) for (auto i : a.Range())
s << i << ": " << a[i] << endl; s << i << ": " << a[i] << std::endl;
return s; return s;
} }
@ -555,10 +556,10 @@ namespace netgen
template <typename T1, typename T2> template <typename T1, typename T2>
inline ostream & operator<< (ostream & s, const NgIndirectArray<T1,T2> & ia) inline std::ostream & operator<< (std::ostream & s, const NgIndirectArray<T1,T2> & ia)
{ {
for (int i = ia.Begin(); i < ia.End(); i++) for (int i = ia.Begin(); i < ia.End(); i++)
s << i << ": " << ia[i] << endl; s << i << ": " << ia[i] << std::endl;
return s; return s;
} }

View File

@ -15,7 +15,7 @@ target_sources(nglib PRIVATE
boundarylayer2d.cpp boundarylayer2d.cpp
) )
target_link_libraries( nglib PRIVATE netgen_metis "$<BUILD_INTERFACE:netgen_python>" ) target_link_libraries( nglib PRIVATE usockets netgen_metis "$<BUILD_INTERFACE:netgen_python>" )
install(FILES install(FILES
adfront2.hpp adfront3.hpp basegeom.hpp bcfunctions.hpp bisect.hpp adfront2.hpp adfront3.hpp basegeom.hpp bcfunctions.hpp bisect.hpp

View File

@ -1,100 +1,231 @@
#include <meshing.hpp> #include "debugging.hpp"
namespace netgen #include <libusockets.h>
{
unique_ptr<Mesh> GetOpenElements( const Mesh & m, int dom = 0 )
{
static Timer t("GetOpenElements"); RegionTimer rt(t);
auto mesh = make_unique<Mesh>();
*mesh = m;
Array<bool, PointIndex> interesting_points(mesh->GetNP()); #include <core/python_ngcore.hpp>
interesting_points = false;
mesh->FindOpenElements(dom); #include "pybind11/gil.h"
NgArray<Element2d> openelements;
openelements = mesh->OpenElements();
for (auto & el : openelements) #ifdef NETGEN_DEBUGGING_GUI
for (auto i : el.PNums()) #include "websockets/App.h"
interesting_points[i] = true; #endif // NETGEN_DEBUGGING_GUI
for (auto & el : mesh->VolumeElements()) namespace netgen {
{ unique_ptr<Mesh> GetOpenElements(const Mesh& m, int dom) {
int num_interesting_points = 0; static Timer t("GetOpenElements");
RegionTimer rt(t);
auto mesh = make_unique<Mesh>();
*mesh = m;
for (auto pi : el.PNums()) Array<bool, PointIndex> interesting_points(mesh->GetNP());
if(interesting_points[pi]) interesting_points = false;
num_interesting_points++;
if(num_interesting_points==0) mesh->FindOpenElements(dom);
el.Delete(); NgArray<Element2d> openelements;
el.SetIndex(num_interesting_points); openelements = mesh->OpenElements();
}
mesh->SetMaterial(1, "1_point"); for (auto& el : openelements)
mesh->SetMaterial(2, "2_points"); for (auto i : el.PNums()) interesting_points[i] = true;
mesh->SetMaterial(3, "3_points");
mesh->SetMaterial(4, "4_points");
mesh->Compress();
mesh->ClearSurfaceElements(); for (auto& el : mesh->VolumeElements()) {
int num_interesting_points = 0;
for (auto & el : openelements) for (auto pi : el.PNums())
mesh->AddSurfaceElement( el ); if (interesting_points[pi]) num_interesting_points++;
return mesh; if (num_interesting_points == 0) el.Delete();
} el.SetIndex(num_interesting_points);
}
unique_ptr<Mesh> FilterMesh( const Mesh & m, FlatArray<PointIndex> points, FlatArray<SurfaceElementIndex> sels, FlatArray<ElementIndex> els ) mesh->SetMaterial(1, "1_point");
{ mesh->SetMaterial(2, "2_points");
static Timer t("GetOpenElements"); RegionTimer rt(t); mesh->SetMaterial(3, "3_points");
auto mesh_ptr = make_unique<Mesh>(); mesh->SetMaterial(4, "4_points");
auto & mesh = *mesh_ptr; mesh->Compress();
mesh = m;
Array<bool, PointIndex> keep_point(mesh.GetNP());
Array<bool, SurfaceElementIndex> keep_sel(mesh.GetNSE());
Array<bool, ElementIndex> keep_el(mesh.GetNE());
mesh.LineSegments().DeleteAll();
keep_point = false;
for(auto pi : points)
keep_point[pi] = true;
auto set_keep = [&] (auto & input, auto & keep_array, auto & els)
{
keep_array = false;
for(auto ind : input)
keep_array[ind] = true;
for(auto ind : Range(els))
{
bool & keep = keep_array[ind];
if(keep) continue;
for(auto pi : mesh[ind].PNums())
keep |= keep_point[pi];
if(!keep)
mesh[ind].Delete();
}
for(auto i = 0; i<els.Size(); i++)
if(els[i].IsDeleted())
{
els.DeleteElement(i);
i--;
}
};
set_keep(sels, keep_sel, mesh.SurfaceElements());
set_keep(els, keep_el, mesh.VolumeElements());
//mesh.Compress();
return mesh_ptr;
}
mesh->ClearSurfaceElements();
for (auto& el : openelements) mesh->AddSurfaceElement(el);
return mesh;
} }
unique_ptr<Mesh> FilterMesh(const Mesh& m, FlatArray<PointIndex> points,
FlatArray<SurfaceElementIndex> sels,
FlatArray<ElementIndex> els) {
static Timer t("GetOpenElements");
RegionTimer rt(t);
auto mesh_ptr = make_unique<Mesh>();
auto& mesh = *mesh_ptr;
mesh = m;
Array<bool, PointIndex> keep_point(mesh.GetNP());
Array<bool, SurfaceElementIndex> keep_sel(mesh.GetNSE());
Array<bool, ElementIndex> keep_el(mesh.GetNE());
mesh.LineSegments().DeleteAll();
keep_point = false;
for (auto pi : points) keep_point[pi] = true;
auto set_keep = [&](auto& input, auto& keep_array, auto& els) {
keep_array = false;
for (auto ind : input) keep_array[ind] = true;
for (auto ind : Range(els)) {
bool& keep = keep_array[ind];
if (keep) continue;
for (auto pi : mesh[ind].PNums()) keep |= keep_point[pi];
if (!keep) mesh[ind].Delete();
}
for (auto i = 0; i < els.Size(); i++)
if (els[i].IsDeleted()) {
els.DeleteElement(i);
i--;
}
};
set_keep(sels, keep_sel, mesh.SurfaceElements());
set_keep(els, keep_el, mesh.VolumeElements());
// mesh.Compress();
return mesh_ptr;
}
#ifdef NETGEN_DEBUGGING_GUI
DebuggingGUI::DebuggingGUI() { Start(); }
DebuggingGUI::~DebuggingGUI() { Stop(); }
struct PerSocketData {};
using WebSocket = uWS::WebSocket<false, true, PerSocketData>;
void DebuggingGUI::Start() {
gui_thread = thread([&]() {
auto a = uWS::App();
loop = a.getLoop();
app = &a;
auto read_file = [](const string& path) {
std::ifstream in(path);
std::stringstream buffer;
buffer << in.rdbuf();
return buffer.str();
};
const string webgui_file = "/home/matthias/src/webgui/dist/webgui.js";
const string main_file = "/home/matthias/a.html";
a.get("/", [&](auto* res, auto* req) { res->end(read_file(main_file)); })
// .any("*", [&](auto* res, auto* req) { cout << "any " << endl; })
.get("/index.html",
[&](auto* res, auto* req) { res->end(read_file(main_file)); })
.get("/webgui.js",
[&](auto* res, auto* req) { res->end(read_file(webgui_file)); })
.connect("/*",
[&](auto* res, auto* req) {
cout << "connect " << req->getUrl() << endl;
})
.listen(7871, [&](auto* token_) {
token = token_;
if (token) {
cout << "Listening on port " << 7871 << endl;
}
});
a.ws<PerSocketData>(
"/ws",
{.compression = uWS::CompressOptions(uWS::DEDICATED_COMPRESSOR_4KB |
uWS::DEDICATED_DECOMPRESSOR),
.maxPayloadLength = 100 * 1024 * 1024,
.idleTimeout = 16,
.maxBackpressure = 100 * 1024 * 1024,
.closeOnBackpressureLimit = false,
.resetIdleTimeoutOnSend = false,
.sendPingsAutomatically = true,
.upgrade = nullptr,
.open =
[&](auto* ws) {
/* Open event here, you may access ws->getUserData() which points
* to a PerSocketData struct */
// cout << "open websocket " << endl;
websockets.insert(ws);
Send(data);
},
.message =
[](auto* ws, std::string_view message, uWS::OpCode opCode) {
cout << "got message " << message << endl;
ws->send(message, opCode, message.length() > 16 * 1024);
},
.dropped =
[](auto* /*ws*/, std::string_view /*message*/,
uWS::OpCode /*opCode*/) {
/* A message was dropped due to set maxBackpressure and
* closeOnBackpressureLimit limit */
cout << "ws: dropped message" << endl;
},
.drain =
[](auto* /*ws*/) {
/* Check ws->getBufferedAmount() here */
cout << "ws: drain" << endl;
},
.close =
[&](auto* ws, int /*code*/, std::string_view /*message*/) {
/* You may access ws->getUserData() here */
// cout << "close" << endl;
websockets.erase(ws);
}});
a.run();
cout << "Exiting GUI thread" << endl;
loop = nullptr;
app = nullptr;
});
}
void DebuggingGUI::Stop() {
cout << "close socket" << endl;
for (auto* ws : websockets) ((WebSocket*)ws)->close();
us_listen_socket_close(0, (struct us_listen_socket_t*)token);
cout << "join thread" << endl;
gui_thread.join();
cout << "joined thread" << endl;
}
void DebuggingGUI::DrawMesh(const string& name, const Mesh& m) {
py::gil_scoped_acquire acquire;
const auto webgui = py::module::import("netgen.webgui");
const auto dumps = py::module::import("json").attr("dumps");
auto smesh = make_shared<Mesh>();
*smesh = m;
const auto py_data =
webgui.attr("Draw")(smesh, py::arg("show") = false).attr("GetData")();
const string d = py::cast<string>(dumps(py_data));
data = json::parse(d);
Send(d);
}
void DebuggingGUI::DrawPoints(const string& name, const Mesh& m,
FlatArray<PointIndex> points) {}
void DebuggingGUI::DrawLines(const string& name, const Mesh& m,
FlatArray<SegmentIndex> lines) {}
void DebuggingGUI::DrawTrigs(const string& name, const Mesh& m,
FlatArray<SurfaceElementIndex> trigs) {}
void DebuggingGUI::DrawTets(const string& name, const Mesh& m,
FlatArray<ElementIndex> tets) {}
void DebuggingGUI::AddComponent(const Mesh& m) {}
void DebuggingGUI::Send(const string& message) {
if (loop) {
((uWS::Loop*)loop)->defer([=]() {
for (auto* ws : websockets) {
((WebSocket*)ws)->send(message, uWS::OpCode::TEXT);
}
});
}
}
DebuggingGUI debug_gui = DebuggingGUI();
#endif // NETGEN_DEBUGGING_GUI
} // namespace netgen

View File

@ -1,12 +1,51 @@
#include "meshclass.hpp" #include "meshing.hpp"
#define NETGEN_DEBUGGING_GUI
namespace netgen #ifdef NETGEN_DEBUGGING_GUI
{ #include "json.hpp"
unique_ptr<Mesh> GetOpenElements( const Mesh & m, int dom = 0 ); using json = nlohmann::json;
#endif // NETGEN_DEBUGGING_GUI
unique_ptr<Mesh> FilterMesh( const Mesh & m, FlatArray<PointIndex> points, FlatArray<SurfaceElementIndex> sels = Array<SurfaceElementIndex>{}, FlatArray<ElementIndex> els = Array<ElementIndex>{} ); namespace netgen {
unique_ptr<Mesh> GetOpenElements(const Mesh& m, int dom = 0);
unique_ptr<Mesh> FilterMesh(
const Mesh& m, FlatArray<PointIndex> points,
FlatArray<SurfaceElementIndex> sels = Array<SurfaceElementIndex>{},
FlatArray<ElementIndex> els = Array<ElementIndex>{});
#ifdef NETGEN_DEBUGGING_GUI
class DebuggingGUI {
public:
DebuggingGUI();
~DebuggingGUI();
} void Start();
void Stop();
void DrawMesh(const string& name, const Mesh& m);
void DrawPoints(const string& name, const Mesh& m,
FlatArray<PointIndex> points);
void DrawLines(const string& name, const Mesh& m,
FlatArray<SegmentIndex> lines);
void DrawTrigs(const string& name, const Mesh& m,
FlatArray<SurfaceElementIndex> trigs);
void DrawTets(const string& name, const Mesh& m,
FlatArray<ElementIndex> tets);
void AddComponent(const Mesh& m);
private:
thread gui_thread;
void *app, *loop, *token;
std::set<void*> websockets;
json data;
void Send(const json& data) { Send(data.dump()); }
void Send(const string& message);
};
extern DebuggingGUI debug_gui;
#endif // NETGEN_DEBUGGING_GUI
} // namespace netgen

View File

@ -709,6 +709,8 @@ namespace netgen
// mesh3d.mglevels = 1; // mesh3d.mglevels = 1;
MeshQuality3d (mesh3d); MeshQuality3d (mesh3d);
} }
debug_gui.DrawMesh("Mesh", mesh3d);
multithread.task = savetask; multithread.task = savetask;
return MESHING3_OK; return MESHING3_OK;