Warning, file /npsim/src/plugins/include/npdet/VolumeDispatchFilter.h was not indexed
or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #ifndef NPDET_VOLUMEDISPATCHFILTER_H
0012 #define NPDET_VOLUMEDISPATCHFILTER_H
0013
0014
0015 #include <DD4hep/Plugins.h>
0016 #include <DDG4/Geant4Action.h>
0017 #include <DDG4/Geant4SensDetAction.h>
0018 #include <DDG4/Geant4FastSimSpot.h>
0019
0020 #include <G4Step.hh>
0021 #include <G4VPhysicalVolume.hh>
0022 #include <G4LogicalVolume.hh>
0023
0024 #include <nlohmann/json.hpp>
0025
0026 #include <memory>
0027 #include <optional>
0028 #include <regex>
0029 #include <string>
0030 #include <vector>
0031
0032
0033 namespace dd4hep {
0034
0035
0036 namespace sim {
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069 class VolumeDispatchFilter : public Geant4Filter {
0070
0071 struct VolumeEntry {
0072 std::string pattern;
0073 Geant4Filter* filter { nullptr };
0074 bool configured { false };
0075 std::optional<std::regex> compiled_regex;
0076 mutable std::size_t steps_accepted { 0 };
0077 mutable std::size_t steps_rejected { 0 };
0078
0079 bool matches(const std::string& lv_name) const {
0080 return compiled_regex && std::regex_search(lv_name, *compiled_regex);
0081 }
0082 };
0083
0084 public:
0085 VolumeDispatchFilter(Geant4Context* c, const std::string& n)
0086 : Geant4Filter(c, n) {
0087 declareProperty("Properties", m_properties_json);
0088 }
0089
0090 virtual ~VolumeDispatchFilter() {
0091
0092 printout(INFO, name().c_str(),
0093 "+++ VolumeDispatchFilter summary: %zu volumes configured",
0094 m_entries.size());
0095 for (const auto& entry : m_entries) {
0096 const char* status = entry.filter ? "OK" : (entry.configured ? "FAILED" : "no filter");
0097 printout(INFO, name().c_str(),
0098 " volume regex '%-30s': %s, accepted %zu / rejected %zu steps",
0099 entry.pattern.c_str(), status,
0100 entry.steps_accepted, entry.steps_rejected);
0101 }
0102 for (auto& entry : m_entries)
0103 if (entry.filter) entry.filter->release();
0104 }
0105
0106 void ensureEntries() const {
0107 if (m_entries_parsed) return;
0108 m_entries.clear();
0109 if (!m_properties_json.empty()) {
0110 try {
0111 auto j = nlohmann::json::parse(m_properties_json);
0112 for (const auto& [vol, val] : j.items()) {
0113 VolumeEntry entry;
0114 entry.pattern = vol;
0115 if (!entry.pattern.empty()) {
0116 try {
0117 entry.compiled_regex.emplace(
0118 entry.pattern,
0119 std::regex_constants::ECMAScript | std::regex_constants::optimize);
0120 } catch (const std::regex_error& e) {
0121 printout(ERROR, name().c_str(),
0122 "Invalid regex '%s': %s", entry.pattern.c_str(), e.what());
0123 }
0124 }
0125
0126
0127 if (val.is_array() && !val.empty()) {
0128 entry.configured = true;
0129 const auto tn = TypeName::split(val[0].get<std::string>());
0130 auto* act = PluginService::Create<Geant4Action*>(
0131 tn.first, const_cast<Geant4Context*>(context()), tn.second);
0132 if (!act) {
0133 printout(ERROR, name().c_str(),
0134 "Failed to create filter '%s' for volume '%s'",
0135 tn.first.c_str(), vol.c_str());
0136 } else {
0137 entry.filter = dynamic_cast<Geant4Filter*>(act);
0138 if (!entry.filter) {
0139 printout(ERROR, name().c_str(),
0140 "Plugin '%s' is not a Geant4Filter", tn.first.c_str());
0141 act->release();
0142 } else {
0143
0144 if (val.size() > 1 && val[1].is_object()) {
0145 for (const auto& [key, pval] : val[1].items()) {
0146 if (entry.filter->hasProperty(key)) {
0147 entry.filter->property(key).str(pval.is_string()
0148 ? pval.get<std::string>()
0149 : pval.dump());
0150 } else {
0151 printout(WARNING, name().c_str(),
0152 "Filter '%s' has no property '%s'",
0153 tn.first.c_str(), key.c_str());
0154 }
0155 }
0156 }
0157 }
0158 }
0159 }
0160 m_entries.push_back(std::move(entry));
0161 }
0162 } catch (const nlohmann::json::exception& e) {
0163 printout(ERROR, name().c_str(),
0164 "Failed to parse Properties JSON: %s", e.what());
0165 }
0166 }
0167 m_entries_parsed = true;
0168 }
0169
0170 virtual bool operator()(const G4Step* step) const override {
0171 ensureEntries();
0172 const G4VPhysicalVolume* pv = step->GetPreStepPoint()->GetPhysicalVolume();
0173 if (!pv) return true;
0174 const std::string lv_name = pv->GetLogicalVolume()->GetName();
0175
0176 for (const auto& entry : m_entries) {
0177 if (!entry.matches(lv_name)) continue;
0178 bool result;
0179 if (!entry.filter) {
0180 if (entry.configured)
0181 printout(ERROR, name().c_str(),
0182 "Filter for volume '%s' was not created; rejecting step",
0183 entry.pattern.c_str());
0184 result = !entry.configured;
0185 } else {
0186 result = (*entry.filter)(step);
0187 }
0188 result ? ++entry.steps_accepted : ++entry.steps_rejected;
0189 return result;
0190 }
0191 return true;
0192 }
0193
0194 virtual bool operator()(const Geant4FastSimSpot* spot) const override {
0195 ensureEntries();
0196 const G4VPhysicalVolume* pv = spot ? spot->volume() : nullptr;
0197 if (!pv) return true;
0198 const std::string lv_name = pv->GetLogicalVolume()->GetName();
0199
0200 for (const auto& entry : m_entries) {
0201 if (!entry.matches(lv_name)) continue;
0202 bool result;
0203 if (!entry.filter) {
0204 if (entry.configured)
0205 printout(ERROR, name().c_str(),
0206 "Filter for volume '%s' was not created; rejecting spot",
0207 entry.pattern.c_str());
0208 result = !entry.configured;
0209 } else {
0210 result = (*entry.filter)(spot);
0211 }
0212 result ? ++entry.steps_accepted : ++entry.steps_rejected;
0213 return result;
0214 }
0215 return true;
0216 }
0217
0218 private:
0219 std::string m_properties_json;
0220 mutable std::vector<VolumeEntry> m_entries;
0221 mutable bool m_entries_parsed { false };
0222 };
0223
0224 }
0225 }
0226
0227 #endif