gsystem
Loading...
Searching...
No Matches
loadGeometry.cc
Go to the documentation of this file.
1
7
8// gsystem
10#include "gsystemConventions.h"
11
12// gemc
13#include "gutilities.h"
14
15// c++
16#include <filesystem>
17
18namespace {
19 bool numeric_value(const std::string& value) {
20 try {
21 size_t parsed = 0;
22 std::stod(value, &parsed);
23 return parsed == value.size();
24 }
25 catch (const std::exception&) { return false; }
26 }
27
28 std::string cad_mesh_reference(const std::string& parameters, const std::string& description) {
29 const auto values = gutilities::getStringVectorFromStringWithDelimiter(parameters, ",");
30 if (values.empty() ||
31 (values.size() == 1 && (values[0] == "NULL" || numeric_value(values[0])))) {
32 return description;
33 }
34 return values[0];
35 }
36
37 void set_resolved_cad_mesh(std::vector<std::string>& row, const std::string& resolved) {
38 constexpr int PARAMETERS_INDEX = 2;
39 constexpr int DESCRIPTION_INDEX = 19;
40 const auto values =
42 if (values.empty() ||
43 (values.size() == 1 && (values[0] == "NULL" || numeric_value(values[0])))) {
44 row[DESCRIPTION_INDEX] = resolved;
45 return;
46 }
47
48 const auto delimiter = row[PARAMETERS_INDEX].find(',');
49 const auto suffix = delimiter == std::string::npos ? "" : row[PARAMETERS_INDEX].substr(delimiter);
50 row[PARAMETERS_INDEX] = resolved + suffix;
51 }
52
53 bool geometry_column_exists(sqlite3* db, const std::string& column_name) {
54 sqlite3_stmt* stmt = nullptr;
55 int rc = sqlite3_prepare_v2(db, "SELECT name FROM PRAGMA_TABLE_INFO('geometry')", -1, &stmt, nullptr);
56 if (rc != SQLITE_OK) { return false; }
57
58 bool exists = false;
59 while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) {
60 const unsigned char* colText = sqlite3_column_text(stmt, 0);
61 if (colText != nullptr && column_name == reinterpret_cast<const char*>(colText)) {
62 exists = true;
63 break;
64 }
65 }
66
67 sqlite3_finalize(stmt);
68 return exists;
69 }
70}
71
72void GSystemSQLiteFactory::loadGeometry(GSystem* system) {
73 // skip ROOT system
74 if (system->getName() == gsystem::ROOTWORLDGVOLUMENAME) { return; }
75
76 // Initialize the DB if needed.
77 if (db == nullptr) { initialize_sqlite_db(system); }
78
79 // Check that db is valid.
80 if (db == nullptr) {
81 log->error(gsystem::ERR_GSQLITEERROR, "Database pointer is still null after initialization.");
82 }
83
84 const std::string placement_column = geometry_column_exists(db, "g4placement_type")
85 ? "g4placement_type"
86 : "'" + std::string(gsystem::DEFAULTG4PLACEMENTTYPE) +
87 "' AS g4placement_type";
88 const std::string sql_query =
89 "SELECT DISTINCT name, solid, parameters, material, mother, position, rotations, " +
90 placement_column +
91 ", mfield, visible, style, color, opacity, digitization, identifier, copyOf, solidsOpr, mirror, "
92 "exist, description FROM geometry WHERE experiment = ? AND system = ? AND variation = ? AND run = ?";
93 sqlite3_stmt* stmt = nullptr;
94 int rc = sqlite3_prepare_v2(db, sql_query.c_str(), -1, &stmt, nullptr);
95 if (rc != SQLITE_OK) {
96 log->error(gsystem::ERR_GSQLITEERROR, "Sqlite error preparing count query in loadGeometry: ",
97 sqlite3_errmsg(db), " (", rc, ") using query: ", sql_query);
98 }
99
100 // Bind parameters.
101 std::string experiment = system->getExperiment();
102 std::string system_name = system->getName();
103 std::string variation = system->getVariation();
104 int runno = system->getRunno();
105
106 rc = sqlite3_bind_text(stmt, 1, experiment.c_str(), -1, SQLITE_STATIC);
107 if (rc != SQLITE_OK) {
108 log->error(gsystem::ERR_GSQLITEERROR, "Error binding experiment: >", experiment, "<, ", sqlite3_errmsg(db));
109 }
110 rc = sqlite3_bind_text(stmt, 2, system_name.c_str(), -1, SQLITE_STATIC);
111 if (rc != SQLITE_OK) {
112 log->error(gsystem::ERR_GSQLITEERROR, "Error binding system name: >", system_name, "<, ", sqlite3_errmsg(db));
113 }
114 rc = sqlite3_bind_text(stmt, 3, variation.c_str(), -1, SQLITE_STATIC);
115 if (rc != SQLITE_OK) {
116 log->error(gsystem::ERR_GSQLITEERROR, "Error binding variation: >", variation, "<, ", sqlite3_errmsg(db));
117 }
118 rc = sqlite3_bind_int(stmt, 4, runno);
119 if (rc != SQLITE_OK) {
120 log->error(gsystem::ERR_GSQLITEERROR, "Error binding run number: >", runno, "<, ", sqlite3_errmsg(db));
121 }
122
123 // Log the expanded SQL for debugging (caller must free it).
124 if (auto sql = sqlite3_expanded_sql(stmt)) {
125 // returns char*
126 log->info(2, sql);
127 sqlite3_free(sql); // need to free the expanded SQL string
128 }
129
130 std::vector<std::string> gvolumePars;
131 std::vector<std::string> cadSearchDirectories;
132 for (const auto& location : possibleLocationOfFiles) {
133 std::error_code ec;
134 if (!std::filesystem::is_directory(location, ec)) { continue; }
135
136 cadSearchDirectories.push_back(location);
137 const auto systemLocation = std::filesystem::path(location) / system->getName();
138 if (std::filesystem::is_directory(systemLocation, ec)) {
139 cadSearchDirectories.push_back(systemLocation.string());
140 }
141 }
142 while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) {
143 int colCount = sqlite3_column_count(stmt);
144 for (int i = 0; i < colCount; i++) {
145 const char* colName = sqlite3_column_name(stmt, i);
146 const unsigned char* colText = sqlite3_column_text(stmt, i);
147
148 log->info(2, "<sqlite> column: ", (colName ? colName : "NULL"), " = ",
149 (colText ? reinterpret_cast<const char*>(colText) : "NULL"), " (column ", i, ")");
150
151 gvolumePars.emplace_back(colText ? reinterpret_cast<const char*>(colText) : "");
152 }
153
154 // CAD rows can coexist with native rows in a sqlite system. Resolve their database-authored
155 // mesh path against the YAML and database locations before the Geant4 CAD builder sees it.
156 if (gvolumePars[1] == gsystem::GSYSTEMCADTFACTORYLABEL) {
157 const auto meshReference = cad_mesh_reference(gvolumePars[2], gvolumePars[19]);
158 auto meshPath = gutilities::searchForFileInLocations(cadSearchDirectories,
159 meshReference);
160 if (!meshPath) {
161 log->warning("SQLite factory: CAD volume <", gvolumePars[0],
162 "> references missing mesh <", meshReference, ">; skipping.");
163 gvolumePars.clear();
164 continue;
165 }
166 set_resolved_cad_mesh(gvolumePars, meshPath.value());
167 }
168
169 system->addGVolume(gvolumePars);
170 gvolumePars.clear();
171 }
172
173 if (rc != SQLITE_DONE) {
174 log->error(gsystem::ERR_GSQLITEERROR, "Sqlite database error in loadGeometry: ",
175 sqlite3_errmsg(db), " (", rc, ")");
176 }
177
178 sqlite3_finalize(stmt);
179}
std::shared_ptr< GLogger > log
std::vector< std::string > possibleLocationOfFiles
List of candidate directories used by file-based factories.
Represents a single detector system (e.g., calorimeter, tracker).
Definition gsystem.h:34
int getRunno() const
Definition gsystem.h:128
std::string getExperiment() const
Definition gsystem.h:126
std::string getVariation() const
Definition gsystem.h:125
void addGVolume(std::vector< std::string > pars)
Build and add a volume from a serialized parameter list.
Definition gsystem.cc:90
std::string getName() const
Definition gsystem.h:123
Conventions and shared constants for the detector-system module.
constexpr char DEFAULTG4PLACEMENTTYPE[]
constexpr char GSYSTEMCADTFACTORYLABEL[]
constexpr int ERR_GSQLITEERROR
constexpr char ROOTWORLDGVOLUMENAME[]
Canonical name for the ROOT/world gvolume entry.
vector< string > getStringVectorFromStringWithDelimiter(const string &input, const string &x)
std::optional< std::string > searchForFileInLocations(const std::vector< std::string > &locations, std::string_view filename)