Skip to content
Snippets Groups Projects

Added new tool that runs a web display and registers the geometry

Merged Whitney Armstrong requested to merge whit/NPDet:master into master
2 files
+ 513
0
Compare changes
  • Side-by-side
  • Inline
Files
2
+ 490
0
 
#include "Math/Vector3D.h"
 
#include "Math/Vector4D.h"
 
#include "Math/VectorUtil.h"
 
#include "TCanvas.h"
 
#include "TLegend.h"
 
#include "TMath.h"
 
#include "TRandom3.h"
 
#include "TFile.h"
 
#include "TH1F.h"
 
#include "TH2F.h"
 
#include "TH1D.h"
 
#include "TH2D.h"
 
#include "TTree.h"
 
#include "TF1.h"
 
#include "TSystem.h"
 
#include "TH1F.h"
 
#include "TH2F.h"
 
#include "TH3F.h"
 
#include "TCanvas.h"
 
#include "THttpServer.h"
 
 
#include <csignal>
 
#include <stdexcept>
 
#include <cstring>
 
#include <vector>
 
#include <map>
 
#include <memory>
 
#include <functional>
 
 
#include "TMessage.h"
 
#include "TMonitor.h"
 
#include "TServerSocket.h"
 
#include "TSocket.h"
 
#include "TFile.h"
 
 
#include <vector>
 
#include <tuple>
 
#include <algorithm>
 
#include <iterator>
 
#include <thread>
 
#include <experimental/filesystem>
 
namespace fs = std::experimental::filesystem;
 
 
#include "DD4hep/Detector.h"
 
#include "DD4hep/Printout.h"
 
#include "DDG4/Geant4Data.h"
 
#include "DDRec/CellIDPositionConverter.h"
 
#include "DDRec/SurfaceManager.h"
 
#include "DDRec/Surface.h"
 
#include "DD4hep/DD4hepUnits.h"
 
 
#include "TApplication.h"
 
#include "TMultiGraph.h"
 
#include "TGraph.h"
 
 
#include "TGeoManager.h"
 
#include "TGeoNode.h"
 
#include "TGeoVolume.h"
 
#include "TEveManager.h"
 
#include "TEveGeoNode.h"
 
#include "TEveGeoShapeExtract.h"
 
#include "TEveGeoShape.h"
 
#include "TEveBrowser.h"
 
#include "TSystem.h"
 
#include "ROOT/TFuture.hxx"
 
 
#include "Math/DisplacementVector3D.h"
 
 
#include <iostream>
 
#include <string>
 
#include <chrono>
 
 
#include "spdlog/spdlog.h"
 
#include "spdlog/sinks/basic_file_sink.h"
 
 
volatile sig_atomic_t sig_caught = 0;
 
 
void handle_sig(int signum) {
 
/* in case we registered this handler for multiple signals */
 
if (signum == SIGINT) {
 
sig_caught = 1;
 
}
 
if (signum == SIGTERM) {
 
sig_caught = 2;
 
}
 
if (signum == SIGABRT) {
 
sig_caught = 3;
 
}
 
}
 
 
#include "clipp.h"
 
using namespace clipp;
 
using std::string;
 
//______________________________________________________________________________
 
 
enum class mode { none, help, list, part };
 
 
struct settings {
 
bool help = false;
 
bool success = false;
 
std::string compact_file = "";
 
std::string infile = "";
 
std::string outfile = "detector_geometry";
 
std::string p_name = "";
 
int part_level = -1;
 
bool level_set = false;
 
int geo_level = -1;
 
bool list_all = false;
 
mode selected = mode::list;
 
int color = 1;
 
double alpha = 1;
 
std::map<std::string,int> part_name_levels;
 
std::map<std::string,int> part_name_colors;
 
std::map<std::string,double> part_name_alphas;
 
int http_port = 8090;
 
string http_host = "127.0.0.1";
 
string in_out_file = "";
 
};
 
//______________________________________________________________________________
 
 
void run_http_server(const settings& s);
 
//void run_part_mode(const settings& s);
 
//______________________________________________________________________________
 
 
template<typename T>
 
void print_usage(T cli, const char* argv0 )
 
{
 
//used default formatting
 
std::cout << "Usage:\n" << usage_lines(cli, argv0)
 
<< "\nOptions:\n" << documentation(cli) << '\n';
 
}
 
//______________________________________________________________________________
 
 
template<typename T>
 
void print_man_page(T cli, const char* argv0 ){
 
//all formatting options (with their default values)
 
auto fmt = clipp::doc_formatting{}
 
.start_column(8) //column where usage lines and documentation starts
 
.doc_column(20) //parameter docstring start col
 
.indent_size(4) //indent of documentation lines for children of a documented group
 
.line_spacing(0) //number of empty lines after single documentation lines
 
.paragraph_spacing(1) //number of empty lines before and after paragraphs
 
.flag_separator(", ") //between flags of the same parameter
 
.param_separator(" ") //between parameters
 
.group_separator(" ") //between groups (in usage)
 
.alternative_param_separator("|") //between alternative flags
 
.alternative_group_separator(" | ") //between alternative groups
 
.surround_group("(", ")") //surround groups with these
 
.surround_alternatives("(", ")") //surround group of alternatives with these
 
.surround_alternative_flags("", "") //surround alternative flags with these
 
.surround_joinable("(", ")") //surround group of joinable flags with these
 
.surround_optional("[", "]") //surround optional parameters with these
 
.surround_repeat("", "..."); //surround repeatable parameters with these
 
//.surround_value("<", ">") //surround values with these
 
//.empty_label("") //used if parameter has no flags and no label
 
//.max_alternative_flags_in_usage(1) //max. # of flags per parameter in usage
 
//.max_alternative_flags_in_doc(2) //max. # of flags per parameter in detailed documentation
 
//.split_alternatives(true) //split usage into several lines for large alternatives
 
//.alternatives_min_split_size(3) //min. # of parameters for separate usage line
 
//.merge_alternative_flags_with_common_prefix(false) //-ab(cdxy|xy) instead of -abcdxy|-abxy
 
//.merge_joinable_flags_with_common_prefix(true); //-abc instead of -a -b -c
 
 
auto mp = make_man_page(cli, argv0, fmt);
 
mp.prepend_section("DESCRIPTION", "Geometry tool for converting compact files to STEP (cad) files.");
 
mp.append_section("EXAMPLES", " $ npdet_to_teve list compact.xml");
 
std::cout << mp << "\n";
 
}
 
//______________________________________________________________________________
 
 
settings cmdline_settings(int argc, char* argv[])
 
{
 
settings s;
 
auto partMode = "part mode:" % repeatable(
 
command("part").set(s.selected,mode::part) % "Select only the first level nodes by name",
 
repeatable(
 
required("-l","--level").set(s.level_set) & integer("level",s.part_level) % "Maximum level navigated to for part",
 
option("-c","--color") & integer("color",s.color),
 
option("-a","--alpha") & number("alpha",s.alpha),
 
value("name")([&](const std::string& p)
 
{
 
s.p_name = p;
 
if(!s.level_set) { s.part_level = -1; }
 
s.level_set = false;
 
std::cout << "s.color " << s.color << "\n";
 
std::cout << "s.alpha " << s.alpha << "\n";
 
s.part_name_levels[p] = s.part_level;
 
s.part_name_colors[p] = s.color;
 
s.part_name_alphas[p] = s.alpha;
 
}) % "Part/Node name (must be child of top node)"
 
)
 
);
 
 
auto lastOpt = " options:" % (
 
option("-h", "--help").set(s.selected, mode::help) % "show help",
 
option("-g","--global_level") & integer("level",s.geo_level),
 
option("-o","--output") & value("out",s.outfile),
 
value("file",s.infile).if_missing([]{
 
std::cout << "You need to provide an input xml filename as the last argument!\n";
 
} ) % "input xml file"
 
);
 
 
 
auto server_cli =
 
((option("-p", "--port") & value("http_port", s.http_port)) %
 
"port to which the http serve attaches. Default: 8090 ",
 
(option("-H", "--host") & value("http_host", s.http_host)) %
 
"Http server host name or IP address. Default: 127.0.0.1",
 
(option("-f", "--file") & value("io_file", s.in_out_file)) %
 
"File used to initialize and save plots. Default: top_folder.root");
 
 
std::string wrong;
 
auto cli = (
 
command("help").set(s.selected, mode::help) | (server_cli, lastOpt),
 
any_other(wrong)
 
);
 
 
assert( cli.flags_are_prefix_free() );
 
 
auto res = parse(argc, argv, cli);
 
 
//if( res.any_error() ) {
 
// s.success = false;
 
// std::cout << make_man_page(cli, argv[0]).prepend_section("error: ",
 
// " The best thing since sliced bread.");
 
// return s;
 
//}
 
s.success = true;
 
 
if(s.selected == mode::help) {
 
print_man_page<decltype(cli)>(cli,argv[0]);
 
};
 
return s;
 
}
 
//______________________________________________________________________________
 
 
 
int main (int argc, char *argv[]) {
 
 
settings s = cmdline_settings(argc,argv);
 
if( !s.success ) {
 
return 1;
 
}
 
 
if(s.selected == mode::help) {
 
return 0;
 
}
 
 
// ------------------------
 
// CLI Checks
 
if( !fs::exists(fs::path(s.infile)) ) {
 
std::cerr << "file, " << s.infile << ", does not exist\n";
 
return 1;
 
}
 
auto has_suffix = [&](const std::string &str, const std::string &suffix) {
 
return str.size() >= suffix.size() &&
 
str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0;
 
};
 
if( !has_suffix(s.outfile,".root") ) {
 
s.outfile += ".root";
 
}
 
//for(const auto& [part_name, part_level] : s.part_name_levels ) {
 
// std::cout << " SOME Part : " << part_name << ", level = " << part_level <<"\n";
 
//}
 
 
// ---------------------------------------------
 
// Run modes
 
//
 
//switch(s.selected) {
 
// case mode::list:
 
// run_list_mode(s);
 
// break;
 
// case mode::part:
 
// run_part_mode(s);
 
// break;
 
// default:
 
// break;
 
//}
 
run_http_server(s);
 
 
return 0;
 
}
 
//______________________________________________________________________________
 
 
 
void run_http_server(const settings& s)
 
{
 
dd4hep::setPrintLevel(dd4hep::WARNING);
 
gErrorIgnoreLevel = kWarning;// kPrint, kInfo, kWarning,
 
 
void (*prev_handler)(int);
 
prev_handler = signal(SIGINT, handle_sig);
 
 
// -------------------------
 
// Get the DD4hep instance
 
dd4hep::Detector& detector = dd4hep::Detector::getInstance();
 
detector.fromCompact(s.infile);
 
 
 
auto serv = new THttpServer((std::string("http:") + s.http_host + ":" +
 
std::to_string(s.http_port) +
 
std::string("?top=geometry&thrds=1;rw;noglobal"))
 
.c_str());
 
 
spdlog::info("Creating display server at http://{}:{}",s.http_host,s.http_port);
 
if( !(serv->IsAnyEngine()) ) {
 
spdlog::error("Failed to start http server.");
 
std::exit(-1);
 
}
 
//_server->SetDefaultPage("online.htm");
 
//_server->SetDefaultPage("draw.htm");
 
serv->SetCors();
 
 
serv->Register("/",detector.manager().GetTopNode());
 
 
// Loop until an interrupt (ctrl-c) is issued
 
while (1) {
 
serv->ProcessRequests();
 
if (sig_caught) {
 
break;
 
}
 
std::this_thread::sleep_for(std::chrono::milliseconds(100));
 
 
}
 
 
signal(SIGINT, prev_handler);
 
 
//std::cout << gGeoManager->GetPath() << "\n";
 
 
//for(const auto& [p,l] : s.part_name_levels) {
 
// bool dir = gGeoManager->cd(p.c_str());
 
// if (!dir) {
 
// std::cerr << p << " not found!\n";
 
// continue;
 
// }
 
// TGeoNode *node = gGeoManager->GetCurrentNode();
 
// int level = gGeoManager->GetLevel();
 
// if( level > l ){
 
// std::cout << "\n" << p << " found at level " << level << " but above selected level of " << l << ")\n";
 
// continue;
 
// }
 
// std::cout << "\n";
 
// std::cout << "Subnodes for \"" << p << "\" (level = " << level << ")\n";
 
// if(node->GetNdaughters() == 0) {
 
// continue;
 
// }
 
// TObjArrayIter node_array_iter(node->GetVolume()->GetNodes());
 
// TGeoNode* a_node = nullptr;
 
// while( (a_node = dynamic_cast<TGeoNode*>(node_array_iter.Next())) ) {
 
// std::cout << p << "/" << a_node->GetName() << "\n";
 
// }
 
 
// //TGeoNode* currentNode = nullptr;
 
// //auto res = new TEveGeoNode(node);
 
// //TGeoIterator nextNode( node->GetVolume() );
 
// //nextNode.SetType(1);
 
// //while( (currentNode = nextNode()) ) {
 
// // auto nlevel = nextNode.GetLevel();
 
// // if( nlevel > l-level ) {
 
// // break;
 
// // }
 
// // //auto daughter = new TEveGeoNode( currentNode );
 
// // //res->AddElement(daughter);
 
// // currentNode->ls();
 
// //}
 
//}
 
}
 
//______________________________________________________________________________
 
 
//void run_part_mode(const settings& s)
 
//{
 
// int root_argc = 0;
 
// char *root_argv[1] = {"npdet_to_teve"};
 
// //argv[0] = "npdet_fields";
 
//
 
// gErrorIgnoreLevel = kWarning;// kPrint, kInfo, kWarning,
 
// TApplication app("tapp", &root_argc, root_argv);
 
//
 
// // Get the DD4hep instance
 
// dd4hep::setPrintLevel(dd4hep::WARNING);
 
// dd4hep::Detector& detector = dd4hep::Detector::getInstance();
 
// detector.fromCompact(s.infile);
 
//
 
// TEveManager::Create();//true,"");
 
//
 
// TEveGeoTopNode* eve_top_n = new TEveGeoTopNode(&(detector.manager()),detector.manager().GetTopNode());
 
// detector.manager().GetTopNode()->SetVisibility(kFALSE);
 
// eve_top_n->SetVisLevel(0);
 
// std::cout << "Path is " << gGeoManager->GetPath() << "\n";
 
//
 
// for(const auto& [p,l] : s.part_name_levels) {
 
// bool dir = gGeoManager->cd(p.c_str());
 
// if (!dir) {
 
// std::cerr << p << " not found!\n";
 
// return;
 
// }
 
// TGeoNode *node = gGeoManager->GetCurrentNode();
 
// if(!node){
 
// std::cerr << " bad node\n";
 
// return;
 
// }
 
// int ilevel = gGeoManager->GetLevel();
 
// if( ilevel > l ){
 
// std::cout << p << " found at level " << ilevel << " but above selected level of " << l << "\n";
 
// //return;
 
// }
 
//
 
// int istate = gGeoManager->GetCurrentNodeId();
 
// std::string ipath = gGeoManager->GetPath();
 
//
 
// auto pcolor = s.part_name_colors.find(p)->second;
 
// auto ptransparency = 100.0*(1.0 - s.part_name_alphas.find(p)->second);
 
//
 
// std::cout << " color " << pcolor << "\n";
 
// std::cout << " ptransparency " << ptransparency << "\n";
 
//
 
// node->GetVolume()->SetLineColor(pcolor);
 
// node->GetVolume()->SetFillColor(pcolor);
 
// node->GetVolume()->SetTransparency(ptransparency);
 
// node->GetVolume()->SetTransparency(ptransparency);
 
//
 
//
 
// TEveGeoNode* res = new TEveGeoNode(node);
 
// std::map<int,TEveGeoNode*> eve_nodes;
 
// eve_nodes[0] = res;
 
//
 
// TGeoIterator nextNode( node->GetVolume() );
 
// int path_index = 0;
 
// TGeoNode* currentNode = nullptr;
 
//
 
// while( (currentNode = nextNode()) ) {
 
// nextNode.SetType(0);
 
// // Not iterator level starts at 1
 
// auto nlevel = nextNode.GetLevel();
 
// if( nlevel > l ) {
 
// continue;
 
// }
 
// //if( path_index == nlevel) {
 
// // if(pcolor != s.part_name_colors.end() ){
 
// currentNode->GetVolume()->SetLineColor(pcolor);
 
// currentNode->GetVolume()->SetFillColor(pcolor);
 
// currentNode->GetVolume()->SetTransparency(ptransparency);
 
// currentNode->GetVolume()->SetTransparency(ptransparency);
 
// // }
 
// TEveGeoNode* daughter = new TEveGeoNode( currentNode );
 
// eve_nodes[nlevel] = daughter;
 
// eve_nodes[nlevel-1]->AddElement(daughter);
 
// //}
 
// //std::cout << nlevel << "\n";
 
// //std::cout << gGeoManager->PushPath() << "\n";
 
//
 
// //res->AddElement(daughter);
 
// currentNode->ls();
 
// }
 
// eve_top_n->AddElement(res);
 
// }
 
//
 
// eve_top_n->SaveExtract(s.outfile.c_str(), "extract", kTRUE);
 
//
 
// //--------------------------------------------
 
// // Now Quit ... it is harder than it should be.
 
// app.Run(kFALSE);
 
// TEveManager::Terminate();
 
// app.Terminate(0);
 
//
 
// //std::cout << "derp1 \n";
 
// //ROOT::EnableImplicitMT(2);
 
// ////TEveManager::Terminate();
 
// //auto wi0 = ROOT::Experimental::Async([&](){app.Run(kFALSE); return std::string("done1");});
 
// //auto wi1 = ROOT::Experimental::Async([&]() {
 
// // //using namespace std::chrono_literals;
 
// // std::cout << "Hello waiter" << std::endl;
 
// // gEve->GetBrowser()->CloseWindow();
 
// // gSystem->ProcessEvents() ;
 
// // std::chrono::seconds sec(2);
 
// // std::this_thread::sleep_for(sec);
 
// // std::cout << "Hello waiter" << std::endl;
 
// // app.Terminate(0);
 
// // std::cout << " " << wi0.get() << std::endl;
 
// // return std::string("done 2");
 
// //});
 
// ////app.Run(kTRUE);
 
// //std::cout << " " << wi1.get() << std::endl;
 
// ////app.Terminate(0);
 
// //// Pass kFALSE if you want application to terminate by itself.
 
// //// Then you just need "return 0;" below (to avoid compiler warnings).
 
// //// Optionally shutdown eve here (not really needed):
 
// //// TEveManager::Terminate();
 
// //std::cout << "derp \n";
 
//}
 
Loading