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