Commit 291747a5 authored by Whitney Armstrong's avatar Whitney Armstrong
Browse files

Added partial geometry extraction to npdet_to_step.

This requires a modified version of ROOT's geocad library.
You can find it at https://github.com/whit2333/root/tree/geocad_improvements

Features:

- 'npdet_to_step list compact.xml'
   This will print names of level 1 volumes. This is useful for the part
   selection.

- 'npdet_to_step part -l 3 EcalBarrel -o EcalBarrel.stp compact.xml'
  This will select only the EcalBarrel geometry and output a new STEP
  file. The Geomtry will only be output up to and include level 3.

- These commands can be added together:
  'npdet_to_step part -l 3 EcalBarrel \
                 part -l 2 HcalBarrel \
                 part -l 4 SiVertexEndcap \
                 -o det_parts.stp  compact.xml'

- See 'npdet_to_step help'
parent a690381c
Pipeline #46 passed with stages
in 1 second
......@@ -20,13 +20,21 @@ target_compile_features(${exe_name}
PUBLIC cxx_trailing_return_types
PRIVATE cxx_variadic_templates )
target_link_libraries(${exe_name} PUBLIC DDCore DDG4 ROOT::Core ROOT::Hist ROOT::GenVector ROOT::Gpad)
install(TARGETS ${exe_name}
EXPORT NPDetTargets
RUNTIME DESTINATION bin )
message("COMPILE_LANGUAGE : ${COMPILE_LANGUAGE}" )
# npdet_to_step needs ROOT's GeoCad library
if(TARGET ROOT::GeoCad)
# get <experimental/filesystem> (will be there in c++17)
add_library(stdc++fs UNKNOWN IMPORTED)
set_property(TARGET stdc++fs PROPERTY IMPORTED_LOCATION "/usr/lib/gcc/x86_64-linux-gnu/7/libstdc++fs.a")
set(exe_name npdet_to_step)
add_executable(${exe_name} src/${exe_name}.cxx)
target_include_directories(${exe_name} PUBLIC
......@@ -34,8 +42,10 @@ if(TARGET ROOT::GeoCad)
target_compile_features(${exe_name}
PUBLIC cxx_auto_type
PUBLIC cxx_trailing_return_types
PRIVATE cxx_variadic_templates )
target_link_libraries(${exe_name} PUBLIC DDCore DDG4 ROOT::Core ROOT::Hist ROOT::GenVector ROOT::Gpad ROOT::GeoCad)
PRIVATE cxx_variadic_templates
#PRIVATE cxx_std_17
)
target_link_libraries(${exe_name} PUBLIC DDCore DDG4 ROOT::Core ROOT::Hist ROOT::GenVector ROOT::Gpad ROOT::GeoCad stdc++fs)
install(TARGETS ${exe_name}
EXPORT NPDetTargets
RUNTIME DESTINATION bin )
......
......@@ -343,7 +343,7 @@ template<>
struct make<unsigned char> {
static inline unsigned char from(const char* s) {
if(!fwd_to_unsigned_int(s)) return (0);
return clamped_on_limits<unsigned char>(std::stoull(s));
return clamped_on_limits<unsigned char>(std::strtoull(s,nullptr,10));
}
};
......@@ -351,7 +351,7 @@ template<>
struct make<unsigned short int> {
static inline unsigned short int from(const char* s) {
if(!fwd_to_unsigned_int(s)) return (0);
return clamped_on_limits<unsigned short int>(std::stoull(s));
return clamped_on_limits<unsigned short int>(std::strtoull(s,nullptr,10));
}
};
......@@ -359,7 +359,7 @@ template<>
struct make<unsigned int> {
static inline unsigned int from(const char* s) {
if(!fwd_to_unsigned_int(s)) return (0);
return clamped_on_limits<unsigned int>(std::stoull(s));
return clamped_on_limits<unsigned int>(std::strtoull(s,nullptr,10));
}
};
......@@ -367,7 +367,7 @@ template<>
struct make<unsigned long int> {
static inline unsigned long int from(const char* s) {
if(!fwd_to_unsigned_int(s)) return (0);
return clamped_on_limits<unsigned long int>(std::stoull(s));
return clamped_on_limits<unsigned long int>(std::strtoull(s,nullptr,10));
}
};
......@@ -375,7 +375,7 @@ template<>
struct make<unsigned long long int> {
static inline unsigned long long int from(const char* s) {
if(!fwd_to_unsigned_int(s)) return (0);
return clamped_on_limits<unsigned long long int>(std::stoull(s));
return clamped_on_limits<unsigned long long int>(std::strtoull(s,nullptr,10));
}
};
......@@ -386,56 +386,56 @@ struct make<char> {
const auto n = std::strlen(s);
if(n == 1) return s[0];
//parse as integer
return clamped_on_limits<char>(std::stoll(s));
return clamped_on_limits<char>(std::strtoll(s,nullptr,10));
}
};
template<>
struct make<short int> {
static inline short int from(const char* s) {
return clamped_on_limits<short int>(std::stoll(s));
return clamped_on_limits<short int>(std::strtoll(s,nullptr,10));
}
};
template<>
struct make<int> {
static inline int from(const char* s) {
return clamped_on_limits<int>(std::stoll(s));
return clamped_on_limits<int>(std::strtoll(s,nullptr,10));
}
};
template<>
struct make<long int> {
static inline long int from(const char* s) {
return clamped_on_limits<long int>(std::stoll(s));
return clamped_on_limits<long int>(std::strtoll(s,nullptr,10));
}
};
template<>
struct make<long long int> {
static inline long long int from(const char* s) {
return (std::stoll(s));
return (std::strtoll(s,nullptr,10));
}
};
template<>
struct make<float> {
static inline float from(const char* s) {
return (std::stof(s));
return (std::strtof(s,nullptr));
}
};
template<>
struct make<double> {
static inline double from(const char* s) {
return (std::stod(s));
return (std::strtod(s,nullptr));
}
};
template<>
struct make<long double> {
static inline long double from(const char* s) {
return (std::stold(s));
return (std::strtold(s,nullptr));
}
};
......@@ -3857,24 +3857,38 @@ public:
//discard other alternatives
match.pos_.skip_alternatives();
}
//if current param is not repeatable, go directly to next
if(!match->repeatable() && !match->is_group()) {
curMatched_ = false;
++match.pos_;
}
else {
curMatched_ = true;
}
if(match.pos_.level() > pos_.level()) {
scopes_.push(pos_.undo_point());
pos_ = std::move(match.pos_);
}
else if(match.pos_.level() < pos_.level()) {
return_to_level(match.pos_.level());
if(is_last_in_current_scope(match.pos_)) {
//if current param is not repeatable -> back to previous scope
if(!match->repeatable() && !match->is_group()) {
curMatched_ = false;
pos_ = std::move(match.pos_);
if(!scopes_.empty()) pos_.undo(scopes_.top());
}
else { //stay at match position
curMatched_ = true;
pos_ = std::move(match.pos_);
}
}
else {
pos_ = std::move(match.pos_);
else { //not last in current group
//if current param is not repeatable, go directly to next
if(!match->repeatable() && !match->is_group()) {
curMatched_ = false;
++match.pos_;
} else {
curMatched_ = true;
}
if(match.pos_.level() > pos_.level()) {
scopes_.push(pos_.undo_point());
pos_ = std::move(match.pos_);
}
else if(match.pos_.level() < pos_.level()) {
return_to_level(match.pos_.level());
}
else {
pos_ = std::move(match.pos_);
}
}
posAfterLastMatch_ = pos_;
}
......@@ -3888,6 +3902,16 @@ public:
}
private:
//-----------------------------------------------------
bool is_last_in_current_scope(const dfs_traverser& pos)
{
if(scopes_.empty()) return pos.is_last_in_path();
//check if we would leave the current scope on ++
auto p = pos;
++p;
return p.level() < scopes_.top().level();
}
//-----------------------------------------------------
void check_repeat_group_start(const scoped_dfs_traverser& newMatch)
{
......@@ -6109,6 +6133,16 @@ inline doc_string doc_label(const parameter& p)
return doc_string{"<?>"};
}
inline doc_string doc_label(const group&)
{
return "<group>";
}
inline doc_string doc_label(const pattern& p)
{
return p.is_group() ? doc_label(p.as_group()) : doc_label(p.as_param());
}
/*************************************************************************//**
*
......
......@@ -17,6 +17,8 @@
#include <tuple>
#include <algorithm>
#include <iterator>
#include <experimental/filesystem>
namespace fs = std::experimental::filesystem;
// DD4hep
// -----
......@@ -36,65 +38,132 @@
#include "TGraph.h"
#include "TGeoToStep.h"
#include "TGeoManager.h"
#include "TGeoNode.h"
#include "TGeoVolume.h"
#include "Math/DisplacementVector3D.h"
#include <iostream>
#include <string>
#include "clipp.h"
#include "clipp.h"
using namespace clipp;
//______________________________________________________________________________
enum class mode { none, help, list, part };
struct settings {
bool success = false;
std::string infile = "";
ROOT::Math::XYZVector start_position{0.0,0.0,0.0};
ROOT::Math::XYZVector direction{0.0,0.0,1.0};
double step_size = 1.0;
bool rec = false;
bool utf16 = false;
bool search = false;
int geo_level = 0;
std::vector<std::string> field_comps;
std::string fmt = "json";
std::vector<std::string> axes;
double x0 = 0.0;
double y0 = 0.0;
double z0 = 0.0;
double x1 = 0.0;
double y1 = 0.0;
double z1 = 0.0;
double x2 = 0.0;
double y2 = 0.0;
double z2 = 0.0;
bool help = false;
bool success = false;
std::string infile = "";
std::string outfile = "detector_geometry";
std::string p_name = "";
int p_level = -1;
std::map<std::string,int> part_name_levels;
bool level_set = false;
int geo_level = -1;
bool list_all = false;
mode selected = mode::part;
};
//______________________________________________________________________________
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_step list compact.xml");
}
//______________________________________________________________________________
settings cmdline_settings(int argc, char* argv[]) {
settings cmdline_settings(int argc, char* argv[])
{
settings s;
auto listMode = "list mode:" % (
command("list").set(s.selected,mode::list) |
command("info").set(s.selected,mode::list) % "list detectors and print info about geometry ",
option("-v","--verbose")
);
auto partMode = "part mode:" % repeatable(
command("part").set(s.selected,mode::part) % "Select only the first level nodes by name",
repeatable(
option("-l","--level").set(s.level_set) & value("level",s.p_level) % "Maximum level navigated to for part",
value("name")([&](const std::string& p)
{
s.p_name = p;
if(!s.level_set) { s.p_level = -1; }
s.part_name_levels[p] = s.p_level;
s.level_set = false;
}) % "Part/Node name (must be child of top node)"
)
);
auto lastOpt = " options:" % (
option("-l","--level") & integer("level",s.geo_level),
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",
//option("-r", "--recursive") % "descend into subdirectories",
option("-h", "--help") % "show help"
% "input xml file"
);
auto cli = (
lastOpt
command("help").set(s.selected, mode::help) | (partMode | listMode , lastOpt)
);
if(!parse(argc, argv, cli)) {
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("DESCRIPTION",
std::cout << make_man_page(cli, argv[0]).prepend_section("error: ",
" The best thing since sliced bread.");
return s;
}
using namespace dd4hep;
s.direction.SetXYZ(s.x2*cm,s.y2*cm,s.z2*cm);
s.direction = s.direction.Unit();
s.start_position.SetXYZ(s.x0*cm,s.y0*cm,s.z0*cm);
s.success = true;
if(s.selected == mode::help) {
print_man_page<decltype(cli)>(cli,argv[0]);
};
return s;
}
//______________________________________________________________________________
......@@ -107,21 +176,51 @@ int main (int argc, char *argv[]) {
return 1;
}
if(s.selected == mode::help) {
return 0;
}
// ------------------------
// TODO: CLI Checks
// 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,".stp") ) {
s.outfile += ".stp";
}
for(const auto& [part_name, part_level] : s.part_name_levels ) {
std::cout << " SOME Part : " << part_name << ", level = " << part_level <<"\n";
}
using namespace dd4hep;
// -------------------------
// Get the DD4hep instance
// Load the compact XML file
dd4hep::Detector& detector = dd4hep::Detector::getInstance();
detector.fromCompact(s.infile);
detector.manager().GetTopVolume()->GetNodes()->Print();
//detector.manager().GetTopVolume()->GetNode(0)->Dump();
if(s.selected == mode::list) {
return 0;
}
TGeoToStep * mygeom= new TGeoToStep( &(detector.manager()) );
mygeom->CreateGeometry(s.geo_level);
if( s.part_name_levels.size() > 1 ) {
mygeom->CreatePartialGeometry( s.part_name_levels, s.outfile.c_str() );
} else if( s.part_name_levels.size() == 1 ) {
// loop of 1
for(const auto& [n,l] : s.part_name_levels){
mygeom->CreatePartialGeometry( n.c_str(), l, s.outfile.c_str() );
}
} else {
mygeom->CreateGeometry(s.outfile.c_str(), s.geo_level);
}
//detector.manager().Export("geometry.gdml");
std::cout << "saved as geometry.stp\n";
return 0;
}
//______________________________________________________________________________
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment