BmnRoot 26.10.0-18-g4e3414f9
Software framework of the BM@N experiment
Loading...
Searching...
No Matches
GeoSetup.cxx
Go to the documentation of this file.
1#include "GeoSetup.h"
2
3#include "BmnNewFieldMap.h"
4#include "FairModule.h"
5#include "FairRunAna.h"
6#include "TGeoBBox.h"
7#include "TGeoBoolNode.h"
9#include "TGeoCone.h"
10#include "TGeoManager.h"
11#include "TGeoMatrix.h"
12#include "TGeoTrd2.h"
13#include "TGeoTube.h"
14#include "TKey.h"
15#include "TSQLResult.h"
16#include "TSQLRow.h"
17#include "TSQLiteServer.h"
18#include "TSystem.h"
19#include "TXMLEngine.h"
20
21#include <cctype>
22#include <cstdlib>
23#include <cstring>
24#include <filesystem>
25#include <iostream>
26#include <stdexcept>
27#include <sys/stat.h> /* stat */
28#include <time.h> /* time */
29#include <unistd.h> /* access, getpid */
30
31bool GeoSetup::exists_file(const char* name)
32{
33 return (access(name, F_OK) != -1);
34}
35
36bool ichar_equals(char a, char b)
37{
38 return std::tolower(static_cast<unsigned char>(a)) == std::tolower(static_cast<unsigned char>(b));
39}
40
41// TSQLRow::GetField() returns nullptr for a NULL field and the server answers are not trusted,
42// so all conversions below tolerate a missing or malformed value instead of crashing or throwing
43static int FieldToInt(const char* field, int defaultValue = 0)
44{
45 if (field == nullptr)
46 return defaultValue;
47 char* end = nullptr;
48 long value = strtol(field, &end, 10);
49 return (end == field) ? defaultValue : static_cast<int>(value);
50}
51
52static uint64_t FieldToUInt64(const char* field, uint64_t defaultValue = 0)
53{
54 if (field == nullptr)
55 return defaultValue;
56 char* end = nullptr;
57 unsigned long long value = strtoull(field, &end, 10);
58 return (end == field) ? defaultValue : static_cast<uint64_t>(value);
59}
60
61static double FieldToDouble(const char* field, double defaultValue = 0.)
62{
63 if (field == nullptr)
64 return defaultValue;
65 char* end = nullptr;
66 double value = strtod(field, &end);
67 return (end == field) ? defaultValue : value;
68}
69
70// setup tags are put into shell command lines, so only the characters used in tag names are allowed
71static bool IsSafeTag(const string& tag)
72{
73 if (tag.empty())
74 return false;
75 for (char c : tag)
76 if (!std::isalnum(static_cast<unsigned char>(c)) && c != '_' && c != '.' && c != '-')
77 return false;
78
79 return true;
80}
81
82// double the single quotes to safely put the value into an SQL string literal
83static string SqlEscape(string_view value)
84{
85 string escaped;
86 escaped.reserve(value.size());
87 for (char c : value) {
88 escaped += c;
89 if (c == '\'')
90 escaped += c;
91 }
92
93 return escaped;
94}
95
96// unique name of a temporary file in the /tmp/$USER/ folder
97TString GeoSetup::GetTmpFileName(const char* baseName)
98{
99 return GetTmpPath() + TString::Format("%s_%d", baseName, gSystem->GetPid());
100}
101
102unsigned long int GeoSetup::GetServerRevision(const char* url)
103{
104 unsigned long int serverRev = 0;
105 // a unique file name in the temporary folder: several jobs can run in the same working directory
106 TString fileName = GetTmpFileName("server_revision.txt");
107 gSystem->Exec(TString::Format("wget -O %s \"%s/get_cur_timestamp.php\" > /dev/null 2>&1", fileName.Data(), url));
108 std::ifstream myFile_Handler;
109 std::string myLine;
110 myFile_Handler.open(fileName.Data());
111 if (myFile_Handler.is_open()) {
112 char* ptr;
113 while (getline(myFile_Handler, myLine)) {
114 serverRev = strtoul(myLine.c_str(), &ptr, 10);
115 break;
116 }
117 myFile_Handler.close();
118 std::remove(fileName.Data());
119 }
120 return serverRev;
121}
122string GeoSetup::GetLastApprovedSetupTag(string_view pattern)
123{
124 std::pair<int, string> res = GetTagName4PatternServer(pattern);
125 if (res.first == 1)
126 return res.second;
127 CloseDB();
128 TString localDbPath = GetLocalDbPath().c_str();
129 res = GetTagName4PatternLocal(pattern, localDbPath);
130 CloseDB();
131 if (res.first == 1)
132 return res.second;
133 string message = "Setup not found for pattern: " + std::string(pattern);
134 LOG(error) << message;
135 throw std::invalid_argument(message);
136}
137std::pair<int, string> GeoSetup::GetTagName4PatternServer(string_view pattern_tag, const char* url)
138{
139 std::pair<int, string> res = std::make_pair<int, string>(0, "");
140 // the pattern is put into a shell command line, so it has to be checked; a string_view is not
141 // necessarily null-terminated, hence the copy
142 std::string pattern(pattern_tag);
143 if (!IsSafeTag(pattern)) {
144 LOG(error) << "ERROR: the setup tag pattern contains forbidden characters: `" << pattern << "`";
145 return res;
146 }
147 // a unique file name in the temporary folder: several jobs can run in the same working directory
148 TString fileName = GetTmpFileName("setup_name.txt");
149 std::remove(fileName.Data());
150 TString command = TString::Format("wget -O %s \"%s/get_setup_name.php?tag=%s\" > /dev/null 2>&1", fileName.Data(),
151 url, pattern.c_str());
152 gSystem->Exec(command);
153 std::ifstream myFile_Handler;
154 std::string myLine;
155 myFile_Handler.open(fileName.Data());
156 if (myFile_Handler.is_open()) {
157 getline(myFile_Handler, myLine);
158 myFile_Handler.close();
159 // the server answer is read, the downloaded file is not needed any more
160 std::remove(fileName.Data());
161 std::size_t found = myLine.find(";");
162 if (found == std::string::npos) {
163 return res;
164 }
165 vector<string> results;
166 istringstream f(myLine);
167 std::string token;
168 while (getline(f, token, ':')) {
169 results.push_back(token);
170 }
171 if (results.size() != 3)
172 return res;
173 res = std::make_pair<int, string>(1, results[0].c_str());
174 }
175 return res;
176}
177
178std::pair<int, uint64_t> GeoSetup::CheckTagOnServer(string_view setup_tag, const char* url)
179{
180 int retval = -1;
181 // a unique file name in the temporary folder: several jobs can run in the same working directory
182 TString fileName = GetTmpFileName("server_setup_list.txt");
183 gSystem->Exec(TString::Format("wget -O %s \"%s/get_setup_list.php\" > /dev/null 2>&1", fileName.Data(), url));
184 std::ifstream myFile_Handler;
185 std::string myLine;
186 std::string sTag(setup_tag);
187 myFile_Handler.open(fileName.Data());
188 if (myFile_Handler.is_open()) {
189 while (getline(myFile_Handler, myLine)) {
190 istringstream f(myLine);
191 string s;
192 while (getline(f, s, ';')) {
193 vector<string> results;
194 std::string token;
195 std::istringstream input;
196 input.str(s);
197 while (getline(input, token, ':')) { // Specify the delimiter
198 results.push_back(token);
199 }
200 if (results.size() < 2)
201 continue; // wrong format
202 std::string tag = results[0];
203 std::string status = results[1];
204 uint64_t upTime = 0;
205 if (results.size() > 2) {
206 // the server answer is not trusted: a non-numeric value must not throw
207 upTime = FieldToUInt64(results[2].c_str());
208 }
209 bool bb = std::equal(tag.begin(), tag.end(), sTag.begin(), sTag.end(), ichar_equals);
210 if (tag.size() == sTag.size() && bb) {
211 myFile_Handler.close();
212 std::remove(fileName.Data());
213 return std::make_pair(FieldToInt(status.c_str(), -1), upTime);
214 }
215 }
216 break;
217 }
218 myFile_Handler.close();
219 std::remove(fileName.Data());
220 }
221 return std::make_pair(retval, 0);
222}
223
224std::pair<int, string> GeoSetup::GetTagName4PatternLocal(string_view pattern_tag, TString& localDbPath)
225{
226 std::pair<int, string> res = std::make_pair<int, string>(0, "");
227 if (exists_file(localDbPath)) {
228 std::ostringstream stringStream;
229 stringStream << "sqlite://" << localDbPath;
230 TSQLiteServer db(stringStream.str().c_str());
231 stringStream.str("");
232 if (db.IsConnected()) {
233 stringStream << "SELECT setup_tag, status, creation_date FROM setup where status=1 and setup_tag like '"
234 << SqlEscape(pattern_tag) << "%' order by creation_date DESC limit 1;";
235 TSQLResult* resQ = db.Query(stringStream.str().c_str());
236 if (resQ != 0) {
237 TSQLRow* row = resQ->Next();
238 if (row != NULL) {
239 const char* name = row->GetField(0);
240 if (name != NULL)
241 res = std::make_pair<int, string>(1, name);
242 }
243 }
244 }
245 }
246 return res;
247}
248unsigned long int GeoSetup::GetLocalRevision(TString& localDbPath)
249{
250 unsigned long int localRev = 0;
251 // char type;
252 if (exists_file(localDbPath)) {
253 std::ostringstream stringStream;
254 stringStream << "sqlite://" << localDbPath;
255 TSQLiteServer db(stringStream.str().c_str());
256 stringStream.str("");
257 if (db.IsConnected()) {
258 stringStream << "select value_field from config where key_field='config_time';";
259 // cout << stringStream.str().c_str() << std::endl;
260 TSQLResult* resQ = db.Query(stringStream.str().c_str());
261 if (resQ != 0) {
262 TSQLRow* row = resQ->Next();
263 if (row != NULL) {
264 const char* ch_time = row->GetField(0);
265 char* ptr;
266 if (ch_time != NULL)
267 localRev = strtoul(ch_time, &ptr, 10);
268 }
269 }
270 }
271 }
272 return localRev;
273}
274
275// check that the directory can be modified to install the Local Geometry DB (e.g. in case of CVMFS)
276bool GeoSetup::IsWritableDir(const char* path)
277{
278 return (access(path, W_OK | X_OK) == 0);
279}
280
281// the unique folder, where the Local Geometry Database is installed by this process
282// instead of the read-only directory, and the process owning the folder
283static string gWritableDbDir;
284static pid_t gWritableDbPid = 0;
285
286// remove the unique folder of the installed database at the process exit
288{
289 // a forked child process must not remove the folder, which is still used by the parent process
290 if (gWritableDbDir.empty() || getpid() != gWritableDbPid)
291 return;
292
293 error_code ec;
294 filesystem::remove_all(gWritableDbDir, ec);
295}
296
297// prepare a writable directory to install the Local Geometry Database to, when the directory of the
298// DBL_FILE_PATH value is read-only. A unique folder is created in the DBL_CACHE_PATH directory, if it is set,
299// otherwise in $TMPDIR or in /tmp/$USER
301{
302 TString baseDir;
303 const char* env_p = getenv("DBL_CACHE_PATH");
304 if (env_p != nullptr) {
305 baseDir = env_p;
306 if (gSystem->ExpandPathName(baseDir)) {
307 LOG(error) << "Cannot expand the DBL_CACHE_PATH value: " << env_p;
308 return "";
309 }
310 } else {
311 const char* tmp_p = getenv("TMPDIR");
312 baseDir = (tmp_p != nullptr && IsWritableDir(tmp_p)) ? TString(tmp_p) : GetTmpPath();
313 }
314 // the folder is unique for the process: jobs installing the database at the same time must not overwrite
315 // the files of each other, also the jobs on different nodes sharing the same directory, e.g. DBL_CACHE_PATH
316 TString dirName = TString::Format("geo_db_%s_%d", gSystem->HostName(), gSystem->GetPid());
317 gSystem->PrependPathName(baseDir.Data(), dirName);
318
319 if (!exists_file(dirName.Data()) && gSystem->mkdir(dirName, true) != 0) {
320 LOG(error) << "ERROR: cannot create the folder for the geometry database: " << dirName;
321 return "";
322 }
323 if (!IsWritableDir(dirName.Data())) {
324 LOG(error) << "ERROR: the folder for the geometry database is not writable: " << dirName;
325 return "";
326 }
327
328 return dirName;
329}
330
331int GeoSetup::installLocalDB(string_view setup_tag, const char* url)
332{
333 CloseDB();
334 TString localDbPath = GetLocalDbPath().c_str();
335 if (localDbPath == "") {
336 LOG(error)
337 << "DBL_FILE_PATH is not set. Please, set DBL_FILE_PATH as a path to the local database file (default, "
338 "'local.db')"
339 << endl;
340 return -1;
341 }
342 FileStat_t file_stat;
343 gSystem->GetPathInfo(localDbPath.Data(), file_stat);
344 if (R_ISDIR(file_stat.fMode)) {
345 LOG(error)
346 << "DBL_FILE_PATH is a path to a folder. Please, set DBL_FILE_PATH as a path to the local database file "
347 "(default, 'local.db')"
348 << endl;
349 return -2;
350 }
351
352 TString dirName(gSystem->DirName(localDbPath.Data()));
353 TString fileName(gSystem->BaseName(localDbPath.Data()));
354 // the database is installed to a writable directory instead of the read-only one given by DBL_FILE_PATH
355 bool isMovedDb = false;
356 if (!exists_file(dirName.Data())) {
357 if (gSystem->mkdir(dirName, true) != 0) {
358 LOG(error) << "ERROR: cannot create folder: " << dirName << endl;
359 return -3;
360 }
361 } else if (!IsWritableDir(dirName.Data())) {
362 // the database directory is read-only (on CVMFS, for example), so the database
363 // is installed to a writable directory, which is used by this process from now on
364 LOG(info) << "The directory of the Local Geometry Database is read-only: " << dirName
365 << ". The database will be installed to a writable directory";
366 TString writableDir = PrepareWritableDbDir();
367 if (writableDir.Length() == 0)
368 return -3;
369 // the folder is removed at the process exit, also if the installation fails below
370 if (gWritableDbPid != getpid()) {
371 gWritableDbDir = writableDir.Data();
372 gWritableDbPid = getpid();
373 atexit(RemoveWritableDbDir);
374 }
375 dirName = writableDir;
376 fileName = "local.db";
377 localDbPath = dirName + "/" + fileName;
378 isMovedDb = true;
379 }
380 // a unique file name in the temporary folder: several jobs can run in the same working directory
381 TString tarName = GetTmpFileName("geo_db.tar");
382 TString command;
383 if (setup_tag.size() == 0)
384 command = TString::Format("wget -O %s \"%s/download_file.php?type=all&tag=all\" > /dev/null 2>&1",
385 tarName.Data(), url);
386 else {
387 std::string tag(setup_tag);
388 if (!IsSafeTag(tag)) {
389 LOG(error) << "ERROR: the setup tag contains forbidden characters: `" << tag << "`";
390 return -7;
391 }
392 command = TString::Format("wget -O %s \"%s/download_file.php?type=s&tag=%s&rev=1\" > /dev/null 2>&1",
393 tarName.Data(), url, tag.c_str());
394 }
395 gSystem->Exec(command);
396 if (!exists_file(tarName.Data())) {
397 LOG(error) << "ERROR: downloading the geometry database file failed, please, check url: " << url << endl;
398 return -4;
399 }
400 gSystem->GetPathInfo(tarName.Data(), file_stat);
401 if (file_stat.fSize == 0) {
402 LOG(error) << "ERROR: downloaded geometry database file has 0 size, please, check url: " << url << endl;
403 gSystem->Unlink(tarName.Data());
404 return -5;
405 }
406 // untar archive with the database file
407 int tarResult =
408 gSystem->Exec(TString::Format("tar -xf %s -C \"%s/\" > /dev/null 2>&1", tarName.Data(), dirName.Data()));
409 // remove temporary archive
410 gSystem->Unlink(tarName.Data());
411 if (tarResult != 0) {
412 LOG(error) << "ERROR: cannot unpack the geometry database archive to the directory: " << dirName << endl;
413 return -8;
414 }
415 if (fileName != "local.db") {
416 gSystem->CopyFile(gSystem->ConcatFileName(dirName.Data(), "local.db"),
417 gSystem->ConcatFileName(dirName.Data(), fileName.Data()), kTRUE);
418 gSystem->Unlink(gSystem->ConcatFileName(dirName.Data(), "local.db"));
419 }
420 // the archive is unpacked, but the database file itself can be absent in it
421 if (!exists_file(localDbPath.Data())) {
422 LOG(error) << "ERROR: no database file found after unpacking the archive: " << localDbPath << endl;
423 return -9;
424 }
425 // the installed database is used by GetLocalDbPath(), GetRootPath() and by the magnetic field map as well;
426 // the path is changed only now, so that the read-only database is still used if the installation failed
427 TString previousDbPath;
428 if (isMovedDb) {
429 previousDbPath = ExpandDbFilePath().c_str();
430 gSystem->Setenv("DBL_FILE_PATH", localDbPath.Data());
431 }
432 if (!OpenLocalGeoDatabase()) {
433 if (isMovedDb)
434 gSystem->Setenv("DBL_FILE_PATH", previousDbPath.Data());
435 return -6;
436 }
437 LOG(info) << "The Local Geometry Database was successfully installed to the directory: " << dirName << endl;
438 return 0;
439}
440
442{
443 m_modules_table.clear();
445 if (m_db != nullptr) {
446 m_db->Close();
447 delete m_db;
448 m_db = nullptr;
449 }
450}
451
452// GeoSetup destructor
454{
455 // CloseDB();
456}
457
458// create connection to the Local Geometry Database and fill the tables with modules and their revisions
460{
461 string fPath = GetLocalDbPath();
462 // const char* env_p = GetDbPath().c_str();//getenv("DBL_FILE_PATH");
463 // LOG(error) <<"OpenLocalGeoDatabase env_p="<<env_p;
464 if (fPath.size() == 0) {
465 LOG(error) << "Please, set DBL_FILE_PATH environment variable before using the Geometry Database";
466 return false;
467 }
468 if (!exists_file(fPath.c_str())) {
469 LOG(error) << "No Database found in " << fPath;
470 return false;
471 }
472 ostringstream stringStream;
473 stringStream << "sqlite://" << fPath;
474
475 LOG(debug1) << "Connecting the Local Geometry Database at path: " << stringStream.str().c_str();
476 // std::cerr<<"Connecting the Local Geometry Database at path: "<<stringStream.str().c_str()<<std::endl;
477 m_db = new TSQLiteServer(stringStream.str().c_str());
478 if (PutModules() != 0) {
479 LOG(error) << "Cannot load detector geometry, please, check DBL_FILE_PATH environment variable";
480 return false;
481 }
482 if (PutModuleRevisions() != 0) {
483 LOG(error) << "Cannot load detector geometry, please, check DBL_FILE_PATH environment variable";
484 return false;
485 }
486
487 return true;
488}
489
490// the shape of an assembly volume is owned by the volume itself, but setups built with FairRoot keep these
491// shapes in the list of shapes as well, where they are deleted the second time, when the geometry is deleted
492static void RemoveAssemblyShapes(TGeoManager* geoManager)
493{
494 TObjArray* shapes = geoManager->GetListOfShapes();
495 TIter nextVolume(geoManager->GetListOfVolumes());
496 int removedCount = 0;
497 while (TGeoVolume* volume = (TGeoVolume*)nextVolume())
498 if (volume->IsAssembly() && shapes->Remove(volume->GetShape()) != nullptr)
499 removedCount++;
500
501 // the setup files built with the fixed FairRoot have no assembly shapes in the list
502 if (removedCount > 0) {
503 shapes->Compress();
504 LOG(info) << removedCount << " assembly shapes were removed from the list of shapes of the geometry";
505 }
506}
507
508//-1 problem to load DB. Require to check DBL_FILE_PATH environment variable.
509//-2 No geometry setup found for the given tag
510//-3 Setup is damaged.
511// load selected geometry setup from the Local Geometry Database and create gGeoManager instance
512int GeoSetup::LoadSetupToGeoManager(string_view setup_tag)
513{
514 if (GetLocalDbPath().empty()) {
515 LOG(error) << "Please, set DBL_FILE_PATH environment variable before using the Geometry Database";
516 return -1;
517 }
518 bool isOpen = false;
520 isOpen = true;
521 TSQLResult* resQ = nullptr;
522 TSQLRow* row = nullptr;
523 ostringstream stringStream;
524 string tag = SqlEscape(setup_tag);
525 // if (revision == nullptr)
526 stringStream << "select setup_id,status,material_id,field_id,file_name,modified_date from setup where "
527 "lower(setup_tag)=lower('"
528 << tag << "') order by creation_date desc;";
529 int sStatus = 0;
530 uint64_t sUpTime = 0;
531 std::pair<int, uint64_t> status;
532 // else
533 // stringStream<<"select idsd,status,idma,idfi,rfile from setup where lower(stag)=lower('"<<setupTag<<"') and
534 // TRIM(revision)=TRIM('"<<revision<<"') order by sdate desc;";
535 if (isOpen) {
536 resQ = m_db->Query(stringStream.str().c_str());
537 if (resQ == nullptr) {
538 // temporary, for support of old database versions without the modified_date column
539 stringStream.str("");
540 stringStream << "select setup_id,status,material_id,field_id,file_name, creation_date from setup where "
541 "lower(setup_tag)=lower('"
542 << tag << "') order by creation_date desc;";
543 resQ = m_db->Query(stringStream.str().c_str());
544 if (resQ == nullptr)
545 LOG(error) << "SQL query was failed while searching the given tag: `" << setup_tag
546 << "`. Setup will download from server.";
547 else
548 row = resQ->Next();
549 } else
550 row = resQ->Next();
551 }
552 if (row != nullptr) {
553 sStatus = FieldToInt(row->GetField(1));
554 sUpTime = FieldToUInt64(row->GetField(5));
555 }
556 if (sStatus == 0) {
557 status = CheckTagOnServer(setup_tag);
558 }
559 if (row == nullptr || (sStatus == 0 && status.second > sUpTime)) {
560 LOG(error) << "No geometry setup found in the local database for `" << setup_tag << "` tag.";
561 delete resQ;
562 resQ = nullptr;
563 if (row != nullptr) {
564 delete row;
565 row = nullptr;
566 }
567 if (status.first >= 0) {
568 int isUpload = -1;
569 if (status.first == 1) {
570 LOG(info) << "Approved geometry setup found on the geometry server:`" << GEO_SERVER_HOST
571 << "`. Downloading...";
572 isUpload = installLocalDB("");
573 } else {
574 LOG(info) << "Not approved geometry setup found on the geometry server:`" << GEO_SERVER_HOST
575 << "`. Downloading";
576 isUpload = installLocalDB(setup_tag);
577 }
578 if (isUpload >= 0) {
579 // In this case do not set modified time for support old DB
580 stringStream.str("");
581 stringStream
582 << "select setup_id,status,material_id,field_id,file_name from setup where lower(setup_tag)=lower('"
583 << tag << "') order by creation_date desc;";
584 resQ = m_db->Query(stringStream.str().c_str());
585 if (resQ == nullptr)
586 LOG(error) << "SQL query was failed while searching the given tag: `" << setup_tag << "`";
587 else
588 row = resQ->Next();
589 } else {
590 LOG(error) << "Cannot download the geometry setup from the server:`" << GEO_SERVER_HOST << "`.";
591 return -2;
592 }
593 } else
594 LOG(error) << "No geometry setup found on the geometry server:`" << GEO_SERVER_HOST << "`.";
595 if (row == nullptr) {
596 LOG(error) << "The geometry setup `" << setup_tag << "` is absent in the Geometry Database";
597 delete resQ;
598 return -2;
599 }
600 }
601
602 m_sid = FieldToInt(row->GetField(0));
603 // int idma = FieldToInt(row->GetField(2));
604 m_fid = FieldToInt(row->GetField(3), -1);
605 TString geoFileField = row->GetField(4) != nullptr ? row->GetField(4) : "";
606 geoFileField = geoFileField.Strip(TString::kBoth);
607 delete row;
608 delete resQ;
609
610 // the setup can be defined only by separate modules (for simulation) without a file with the full geometry
611 if (geoFileField.IsNull()) {
612 LOG(error) << "The geometry setup `" << setup_tag
613 << "` has no ROOT file with the full geometry in the Geometry Database";
614 return -3;
615 }
616 TString geoFileName = GetRootPath() + geoFileField;
617
618 TFile* geoFile = new TFile(geoFileName, "READ");
619 if (geoFile->IsZombie() || !geoFile->IsOpen()) {
620 LOG(error) << "ERROR: could not open ROOT file with geometry: " + geoFileName;
621 delete geoFile;
622 return -3;
623 }
624 TList* keyList = geoFile->GetListOfKeys();
625 TIter next(keyList);
626 TKey* key = (TKey*)next();
627 if (key == nullptr || !TString(key->GetClassName()).BeginsWith("TGeoManager")) {
628 LOG(error) << "ERROR: TGeoManager is not top element in geometry file " + geoFileName;
629 delete geoFile;
630 return -3;
631 }
632 // the read geometry registers itself as gGeoManager, so the file can be closed (as TGeoManager::Import does)
633 key->ReadObj();
634 delete geoFile;
635 if (gGeoManager != nullptr)
637
638 m_setupTag = string(setup_tag);
639 return 0;
640}
641
642// load selected geometry for simulation application from the Geometry Database.
643int GeoSetup::LoadSetupToFairRunSim(string_view setup_tag, const char* localSettings)
644{
645 if (localSettings != nullptr) {
646 // the path can contain environment variables, e.g. "$VMCWORKDIR/my_setup.xml"
647 TString localSettingsPath(localSettings);
648 gSystem->ExpandPathName(localSettingsPath);
649 LoadLocalSettings(localSettingsPath.Data());
650 }
651
652 // int random_variable;
653 /* if (url != nullptr)
654 {
655 srand(time(NULL));
656 random_variable = rand();
657 //cout<<random_variable<<endl;
658 ostringstream stringStream;
659 // stringStream<<"wget -O test2.tar \""<<url<<"?type=s&tag="<<setupTag<<"&dirname="<<random_variable<<"\"";
660 http://cbmdb.jinr.ru/geometry8/download_file.php?type=all&tag=all stringStream<<"wget -O test2.tar
661 \""<<url<<"/download_file.php?type=all&tag=all&dirname="<<random_variable<<"\" >/dev/null ";
662 system(stringStream.str().c_str());
663
664 stringStream.str("");
665 stringStream<<"tar -xf test2.tar >/dev/null";
666 system(stringStream.str().c_str());
667
668 stringStream.str("");
669 stringStream<<"rm test2.tar";
670 system(stringStream.str().c_str());
671
672 stringStream.str("");
673 stringStream<<gSystem->pwd()<<"/"<<random_variable<<"/storage/";
674 gSystem->Setenv("DBL_ROOT_PATH", stringStream.str().c_str());
675
676 stringStream.str("");
677 stringStream<<gSystem->pwd()<<"/"<<random_variable<<"/local.db";
678 gSystem->Setenv("DBL_FILE_PATH", stringStream.str().c_str());
679 }*/
680 /* const char* env_p = GetDbPath().c_str();//getenv("DBL_FILE_PATH");
681 if (env_p == nullptr) {
682 LOG(error) << "Please, set DBL_FILE_PATH environment variable before using the Geometry Database";
683 return -1;
684 }*/
685 bool isOpen = false;
687 isOpen = true;
688 TSQLResult* resQ = nullptr;
689 TSQLRow* row = nullptr;
690
691 ostringstream stringStream;
692 string tag = SqlEscape(setup_tag);
693 // if (revision == nullptr)
694 stringStream
695 << "select setup_id,status,material_id,field_id,modified_date from setup where lower(setup_tag)=lower('" << tag
696 << "') order by creation_date desc;"; // KG если я правильно понял, то нужно брать по-умолчанию,
697 // самый новый релиз?
698 // else
699 // stringStream<<"select idsd,status,idma,idfi from setup where stag='"<<setupTag<<"' and
700 // TRIM(revision)=TRIM('"<<revision<<"') order by sdate desc;";
701 LOG(debug1) << stringStream.str().c_str();
702 int sStatus = 0;
703 uint64_t sUpTime = 0;
704 std::pair<int, uint64_t> status;
705 if (isOpen) {
706 resQ = m_db->Query(stringStream.str().c_str());
707 if (resQ == nullptr) {
708 // temprorary for support old versions
709 stringStream.str("");
710 stringStream
711 << "select setup_id,status,material_id,field_id,creation_date from setup where lower(setup_tag)=lower('"
712 << tag << "') order by creation_date desc;";
713 resQ = m_db->Query(stringStream.str().c_str());
714 if (resQ == nullptr)
715 LOG(error) << "SQL query was failed while searching the given tag: `" << setup_tag
716 << "`. Setup will download from server.";
717 else
718 row = resQ->Next();
719 // return -2;
720 } else
721 row = resQ->Next();
722 }
723 if (row != nullptr) {
724 sStatus = FieldToInt(row->GetField(1));
725 sUpTime = FieldToUInt64(row->GetField(4));
726 }
727 if (sStatus == 0) {
728 status = CheckTagOnServer(setup_tag);
729 }
730 if (row == nullptr || (sStatus == 0 && status.second > sUpTime)) {
731 LOG(error) << "No geometry setup found in the local database for `" << setup_tag << "` tag." << status.first;
732 delete resQ;
733 resQ = nullptr;
734 if (status.first >= 0) {
735 int isUpload = -1;
736 if (status.first == 1) {
737 LOG(info) << "Approved geometry setup found on the geometry server:`" << GEO_SERVER_HOST
738 << "`. Downloading...";
739 isUpload = installLocalDB("");
740 } else {
741 LOG(info) << "Not approved geometry setup found on the geometry server:`" << GEO_SERVER_HOST
742 << "`. Downloading...";
743 isUpload = installLocalDB(setup_tag);
744 }
745 if (isUpload >= 0) {
746 // AE added for support old version
747 stringStream.str("");
748 stringStream
749 << "select setup_id,status,material_id,field_id,file_name from setup where lower(setup_tag)=lower('"
750 << tag << "') order by creation_date desc;";
751
752 resQ = m_db->Query(stringStream.str().c_str());
753 if (resQ == nullptr)
754 LOG(error) << "SQL query was failed while searching the given tag: `" << setup_tag << "`";
755 else
756 row = resQ->Next();
757 } else {
758 LOG(error) << "Cannot download the geometry setup from the server:`" << GEO_SERVER_HOST << "`.";
759 return -2;
760 }
761 } else
762 LOG(error) << "No geometry setup found on the geometry server:`" << GEO_SERVER_HOST << "`.";
763 if (row == nullptr) {
764 LOG(error) << "The geometry setup `" << setup_tag << "` is absent in the Geometry Database";
765 return -2;
766 }
767 }
768
769 FairRunSim* fRun = FairRunSim::Instance();
770 if (fRun == nullptr) {
771 fRun = new FairRunSim();
772 LOG(info) << "New FairRunSim instance has been created";
773 }
774
775 m_sid = FieldToInt(row->GetField(0));
776 int idma = FieldToInt(row->GetField(2));
777 m_fid = FieldToInt(row->GetField(3), -1);
778 if (idma > 0) {
779 delete row;
780 delete resQ;
781
782 stringStream.str("");
783 stringStream << "select matag,file_name from material where material_id=" << idma << ";";
784 resQ = m_db->Query(stringStream.str().c_str());
785
786 if (resQ == 0 || resQ->GetRowCount() == 0) {
787 LOG(info) << "Materials were not found";
788 delete resQ;
789 } else {
790 row = resQ->Next();
791 /* const char* media_path = row->GetField(1);
792
793 TString Mat = getenv("GEOMPATH");
794 if (Mat.IsNull()) {
795 Mat = ((TString)getenv("VMCWORKDIR")) + "/geometry/";
796 Mat.ReplaceAll("//", "/");
797 } else {
798 Mat.ReplaceAll("//", "/");
799 if (!Mat.EndsWith("/"))
800 Mat += "/";
801 }
802
803 string workP(Mat.Data());
804 LOG(debug1) << "Working geometry directory: " << workP;
805
806 size_t found = workP.find('/');
807 TString in("");
808 if (found != string::npos) {
809 while ((found = workP.find('/', found + 1)) != string::npos) {
810 LOG(debug1) << "found:" << found;
811 in += "../";
812 }
813 }
814 in += GetRootPath() + media_path;
815 */
816 if (row == nullptr)
817 LOG(info) << "Materials were not found";
818 else {
819 const char* materialFile = row->GetField(1);
820 TString in = (materialFile != nullptr ? materialFile : "");
821 fRun->SetMaterials(in.Data());
822 m_materialFile = in.Data();
823
824 delete row;
825 }
826 delete resQ;
827 }
828 } else {
829 delete row;
830 delete resQ;
831 }
832 LOG(info) << "Load geometry with tag=" << setup_tag << " from database";
833 LOG(debug1) << "setup_id = " << m_sid << "; material_id = " << idma << "; filed_id = " << m_fid << endl;
834 stringStream.str("");
835 stringStream << "select setup_module_id from sms where setup_id=" << m_sid << ";";
836 resQ = m_db->Query(stringStream.str().c_str());
837 if (resQ == 0 || resQ->GetRowCount() == 0) {
838 LOG(error) << "ERROR: no modules found";
839 return -3;
840 }
841 while ((row = resQ->Next()) != nullptr) {
842 stringStream.str("");
843 const char* idsm = row->GetField(0);
844 int idsmI = FieldToInt(idsm);
845 LOG(debug1) << "module=" << idsmI << std::endl;
846 // if (subSetup < 0 || subSetup == idsmI){ //check subset
847 int res = LoadModuleToFairRunSim(idsmI, fRun);
848 if (res == -1) {
849 LOG(error) << "ERROR: no file for the setup module " << idsmI << " was found";
850 return -3;
851 }
852 delete row;
853 }
854 delete resQ;
855 for (const auto& item : m_moduleAdd) {
856 AddModuleToFairRunSim(item, fRun);
857 // std::cout << item << " ";
858 }
859
860 /* if (url != nullptr)
861 {
862 stringStream.str("");
863 stringStream<<"rm -rf "<<random_variable<<"/local.db";
864 system(stringStream.str().c_str());
865
866 stringStream.str("");
867 stringStream<<"rm -rf "<<random_variable;
868 system(stringStream.str().c_str());
869
870 cout<<"DBL_ROOT_PATH="<<getRootPath()<<endl; //KG should be DBL_PATH variables restored?
871 }*/
872 m_setupTag = string(setup_tag);
873 return 0;
874}
875
876// get field map of selected geometry
878{
879 // return magnetic field if exists
880 if (m_field != nullptr)
881 return m_field;
882
883 if (m_db == nullptr) {
884 LOG(error) << "Geometry Database is not loaded";
885 return nullptr;
886 }
887 if (m_fid == -1) {
888 LOG(debug1) << "Selected Geometry Database has no magnetic field";
889 return nullptr;
890 }
891
892 // get field map for the current id from the Geometry Database
893 ostringstream stringStream;
894 stringStream << "select file_name,scale,x,y,z from field where field_id=" << m_fid << ";";
895 TSQLResult* resQ = m_db->Query(stringStream.str().c_str());
896 if (resQ == nullptr) {
897 LOG(error) << "SQL query was failed while searching magnetic field for id: `" << m_fid << "`";
898 return nullptr;
899 }
900 if (resQ->GetRowCount() == 0) {
901 LOG(error) << "ERROR: no selected magnetic field in the Geometry Database for id=" << m_fid;
902 delete resQ;
903 return nullptr;
904 }
905
906 TSQLRow* row = resQ->Next();
907 if (row == nullptr) {
908 LOG(error) << "ERROR: no selected magnetic field in the Geometry Database for id=" << m_fid;
909 delete resQ;
910 return nullptr;
911 }
912
913 stringStream.str("");
914 stringStream << (row->GetField(0) != nullptr ? row->GetField(0) : "");
915 double sc = FieldToDouble(row->GetField(1));
916 delete row;
917 delete resQ;
918
919 // to be changed to dynamic magnetic class got by the Geometry Database
920 BmnNewFieldMap* pBmnNewFieldMap = new BmnNewFieldMap();
921 pBmnNewFieldMap->SetFileName(stringStream.str().c_str());
922 // scale the magnetic field: zero scale turns the field off, a negative one means the default scale of the database
923 if (scale >= 0)
924 pBmnNewFieldMap->SetScale(scale);
925 else
926 pBmnNewFieldMap->SetScale(sc);
927
928 m_field = pBmnNewFieldMap;
929 return m_field;
930}
931
932// get parameter file by given detector name
933string GeoSetup::GetParameterFile(string_view name)
934{
935 if (name == "") {
936 LOG(error) << "Detector name for the parameter file is not set";
937 return "";
938 }
939 if (m_db == nullptr) {
940 LOG(error) << "The Geometry Database is not connected";
941 return "";
942 }
943
944 TString sname(name);
945 int index = GetModuleIndex(sname);
946 if (index < 0) {
947 LOG(error) << "The detector name \'" << sname << "\'does not exist in the Geometry Database";
948 return "";
949 }
950 LOG(debug1) << "The detector name \'" << sname << "\'exists in the Geometry Database";
951
952 ostringstream stringStream;
953 stringStream
954 << "select sm.fpar from sms s INNER JOIN setup_module sm on s.idsm=sm.idsm INNER JOIN file f on sm.idf=f.idf "
955 "INNER JOIN module_revision mr on f.idm=mr.idmr where idsd="
956 << m_sid << " and mr.idm=" << index << ";";
957 LOG(debug1) << "Request \'" << stringStream.str().c_str() << "\'.";
958 TSQLResult* resQ = m_db->Query(stringStream.str().c_str());
959 if (resQ == nullptr) {
960 LOG(info) << "SQL query was failed while searching parameter file for detector `" << sname << "`";
961 return "";
962 }
963 TSQLRow* row = resQ->Next();
964 if (row == nullptr) {
965 LOG(info) << "Parameter file for detector `" << sname << "` not found";
966 delete resQ;
967 return "";
968 }
969
970 // the field points to the memory owned by the row, so it has to be copied before the row is deleted
971 const char* file = row->GetField(0);
972 string parameterFile = (file != nullptr ? file : "");
973 delete row;
974 delete resQ;
975
976 if (parameterFile.empty()) {
977 LOG(info) << "Parameter file for detector `" << sname << "` does not exist in the Geometry Database";
978 return "";
979 }
980
981 return parameterFile;
982}
983
984// get the material file of the current setup
986{
987 // the file name is read by LoadSetupToFairRunSim(), it is requested here only if the setup geometry
988 // was loaded by another way, e.g. by LoadSetupToGeoManager()
989 if (!m_materialFile.empty())
990 return m_materialFile;
991
992 if (m_sid == -1) {
993 LOG(error) << "The geometry setup is not loaded";
994 return "";
995 }
996 if (m_db == nullptr) {
997 LOG(error) << "The Geometry Database is not connected";
998 return "";
999 }
1000
1001 ostringstream stringStream;
1002 stringStream << "select m.file_name from setup s INNER JOIN material m on m.material_id=s.material_id where "
1003 "s.setup_id="
1004 << m_sid << ";";
1005 TSQLResult* resQ = m_db->Query(stringStream.str().c_str());
1006 if (resQ == nullptr) {
1007 LOG(info) << "SQL query was failed while searching the material file of the setup";
1008 return "";
1009 }
1010 TSQLRow* row = resQ->Next();
1011 if (row == nullptr) {
1012 LOG(info) << "Material file of the setup was not found in the Geometry Database";
1013 delete resQ;
1014 return "";
1015 }
1016
1017 // the field points to the memory owned by the row, so it has to be copied before the row is deleted
1018 const char* file = row->GetField(0);
1019 m_materialFile = (file != nullptr ? file : "");
1020 delete row;
1021 delete resQ;
1022
1023 return m_materialFile;
1024}
1025
1026// expanded value of the DBL_FILE_PATH environment variable; "" if it is not set or cannot be expanded
1028{
1029 const char* env_p = getenv("DBL_FILE_PATH");
1030 if (env_p == nullptr) {
1031 LOG(debug1) << "DBL_FILE_PATH environment variable is not set";
1032 return "";
1033 }
1034 // the TString overload reports an error by the return value and, unlike the char* one,
1035 // does not allocate a buffer that has to be deleted by the caller
1036 TString path(env_p);
1037 if (gSystem->ExpandPathName(path)) {
1038 LOG(error) << "Cannot expand the DBL_FILE_PATH value: " << env_p;
1039 return "";
1040 }
1041
1042 return string(path.Data());
1043}
1044
1045// get path to the location of the Local Geometry Database
1047{
1048 string rootPath = ExpandDbFilePath();
1049 if (rootPath.empty())
1050 return "";
1051
1052 struct stat st;
1053 if (stat(rootPath.c_str(), &st) == 0)
1054 if (!S_ISDIR(st.st_mode)) {
1055 TString dirName(gSystem->DirName(rootPath.c_str()));
1056 rootPath = dirName.Data();
1057 }
1058
1059 rootPath += "/storage/";
1060
1061 return rootPath;
1062}
1063
1065{
1066 string rootPath = ExpandDbFilePath();
1067 if (rootPath.empty())
1068 return "";
1069
1070 struct stat st;
1071 if (stat(rootPath.c_str(), &st) == 0)
1072 if (!S_ISDIR(st.st_mode)) {
1073 return rootPath;
1074 }
1075
1076 rootPath += "/local.db";
1077 return rootPath;
1078}
1079
1080// get path to a temporary directory (/tmp/$USER/), and create if absent
1082{
1083 if (m_tmpFolder.Length() != 0)
1084 return m_tmpFolder;
1085
1086 UserGroup_t* user = gSystem->GetUserInfo();
1087 string login(user->fUser.Data());
1088 m_tmpFolder = "/tmp/" + login + "/";
1089 system("mkdir -p " + m_tmpFolder);
1090
1091 return m_tmpFolder;
1092}
1093
1094// load local settings from the file for all setup modules
1095bool GeoSetup::LoadLocalSettings(const char* fileName)
1096{
1097 LOG(info) << "Load local settings of geometry DB from '" << fileName << "'";
1098 TXMLEngine* xml = new TXMLEngine;
1099 XMLDocPointer_t xmldoc = xml->ParseFile(fileName);
1100 if (xmldoc == 0) {
1101 LOG(error) << "Selected file has not XML format: " << fileName;
1102 delete xml;
1103 return false;
1104 }
1105
1106 m_moduleEdit.clear();
1107
1108 XMLNodePointer_t mainnode = xml->DocGetRootElement(xmldoc);
1109 XMLNodePointer_t child = xml->GetChild(mainnode);
1110 while (child != 0) {
1111 TString chName = xml->GetNodeName(child);
1112 if (chName.CompareTo("editSetupModule") == 0) {
1113 setup_module_ptr sNode = new setup_module();
1114 sNode->xMove = 0;
1115 sNode->yMove = 0;
1116 sNode->zMove = 0;
1117 sNode->enable = true;
1118 sNode->type = TString("");
1119
1120 XMLAttrPointer_t attr = xml->GetFirstAttr(child);
1121 while (attr != 0) {
1122 TString aName = xml->GetAttrName(attr);
1123 TString aValue = xml->GetAttrValue(attr);
1124 if (aName.CompareTo("tag") == 0) {
1125 aValue.ToUpper();
1126 sNode->type = aValue;
1127 } else if (aName.CompareTo("moveX") == 0) {
1128 sNode->xMove = aValue.Atof();
1129 } else if (aName.CompareTo("moveY") == 0) {
1130 sNode->yMove = aValue.Atof();
1131 } else if (aName.CompareTo("moveZ") == 0) {
1132 sNode->zMove = aValue.Atof();
1133 } else if (aName.CompareTo("file_path") == 0) {
1134 gSystem->ExpandPathName(aValue);
1135 sNode->file_path = aValue;
1136 } else if ((aName.CompareTo("enable") == 0)
1137 && (aValue.CompareTo("false") == 0 || aValue.CompareTo("False") == 0
1138 || aValue.CompareTo("FALSE") == 0))
1139 sNode->enable = false;
1140
1141 LOG(debug1) << "attr: " << xml->GetAttrName(attr) << " value: " << xml->GetAttrValue(attr);
1142
1143 attr = xml->GetNextAttr(attr);
1144 }
1145
1146 // int ii = GetModuleIndex(sNode->type);
1147 // if(!sNode->enable)
1148 // LOG(info)<<"Disable module with tag="<<sNode->type;//<<" and ModuleId="<<ii;
1149 m_moduleEdit.insert(pair<TString, setup_module_ptr>(sNode->type, sNode));
1150 } else if (chName.CompareTo("addSetupModule") == 0) {
1151 module_r_ptr module = new module_r();
1152 XMLAttrPointer_t attr = xml->GetFirstAttr(child);
1153 while (attr != 0) {
1154 TString aName = xml->GetAttrName(attr);
1155 TString aValue = xml->GetAttrValue(attr);
1156 if (aName.CompareTo("class_name") == 0)
1157 module->class_name = aValue;
1158 else if (aName.CompareTo("file_path") == 0) {
1159 gSystem->ExpandPathName(aValue);
1160 module->file_path = aValue;
1161 } else if (aName.CompareTo("args") == 0)
1162 module->args = aValue;
1163 if ((aName.CompareTo("active") == 0)
1164 && (aValue.CompareTo("false") == 0 || aValue.CompareTo("False") == 0
1165 || aValue.CompareTo("FALSE") == 0))
1166 module->active = false;
1167 attr = xml->GetNextAttr(attr);
1168 }
1169 m_moduleAdd.push_back(module);
1170 }
1171 child = xml->GetNext(child);
1172 }
1173
1174 xml->FreeDoc(xmldoc);
1175 delete xml;
1176 return true;
1177}
1178
1179// get module name by index; return "Unknown" if not found
1181{
1182 map<int, TString>::iterator it = m_modules_table.find(dbModuleUndex);
1183 if (it != m_modules_table.end())
1184 return it->second;
1185 else {
1186 LOG(error) << "Unknown module type with id=" << dbModuleUndex;
1187 return TString("Unknown");
1188 }
1189}
1190
1191// get module index by name; return -1 if not found
1193{
1194 map<int, TString>::iterator it;
1195 for (it = m_modules_table.begin(); it != m_modules_table.end(); ++it)
1196 if ((it->second).CompareTo(name, TString::ECaseCompare::kIgnoreCase) == 0)
1197 return it->first;
1198
1199 return -1;
1200}
1201
1202// get module_r_ptr (pointer to the module revision) by revision number
1204{
1205 map<int, module_r_ptr>::iterator it = m_modules_revision_table.find(dbModuleRev);
1206 if (it != m_modules_revision_table.end())
1207 return it->second; //.class_name;
1208
1209 module_r_ptr mr = nullptr;
1210 return mr;
1211}
1212
1213// get module ID by revision number; return -1 if not found
1214int GeoSetup::GetModuleId(int dbModuleRev)
1215{
1216 map<int, module_r_ptr>::iterator it = m_modules_revision_table.find(dbModuleRev);
1217 if (it != m_modules_revision_table.end())
1218 return it->second->idm;
1219
1220 return -1;
1221}
1222
1223// get module type by revision number
1225{
1226 return GetModuleName(GetModuleId(dbModuleRev));
1227}
1228
1229// get root volume in the TFile object (first search for TGeoManager)
1231{
1232 TKey* key;
1233 TGeoManager* geoManager = nullptr;
1234 TList* l = f->GetListOfKeys();
1235 TIter next(l);
1236 while ((key = (TKey*)next())) {
1237 if (strcmp(key->GetClassName(), "TGeoManager") != 0)
1238 continue;
1239 geoManager = (TGeoManager*)key->ReadObj();
1240 geoManager->cd();
1241 TGeoNode* top = geoManager->GetNode(0);
1242 if (top == nullptr || top->GetNdaughters() == 0) {
1243 LOG(error) << "ERROR: geometry in the file " << f->GetName() << " has no daughter volume";
1244 return nullptr;
1245 }
1246 return (TGeoVolume*)top->GetDaughter(0)->GetVolume();
1247 }
1248
1249 // if TGeoManager was not found in the file
1250 key = (TKey*)l->At(0); // Get the first key in the list
1251 if (key == nullptr) {
1252 LOG(error) << "ERROR: no keys found in the geometry file " << f->GetName();
1253 return nullptr;
1254 }
1255 TGeoVolume* volume = dynamic_cast<TGeoVolume*>(key->ReadObj());
1256
1257 return volume;
1258}
1259
1260// add FairModule defined by revision number and geometry file path to the FairRunSim instance
1261bool GeoSetup::AddModuleToFairRunSim(int dbModuleRev, const char* path, FairRunSim* fRun)
1262{
1263 module_r_ptr mr = GetModuleRevision(dbModuleRev);
1264 if (mr == nullptr) {
1265 LOG(error) << "ERROR: no module revision with id=" << dbModuleRev << " in the Geometry Database";
1266 return false;
1267 }
1268
1269 // TClass* cl = TClass::GetClass(mr->class_name);
1270 // FairModule* f_cl = (FairModule*) cl->New();
1271 // cout<<"TClass:"<<cl<<endl; f_cl->Dump();
1272
1273 TString type_name;
1274 if (mr->args.Length() > 0) {
1275 type_name = mr->args;
1276 // f_cl->SetName(mr.args);
1277 } else {
1278 type_name = GetModuleType(dbModuleRev);
1279 // f_cl->SetName(getModuleType(dbModuleRev));
1280 }
1281
1282 TString command = "new " + mr->class_name + "(\"" + type_name + "\"";
1283 if (mr->active)
1284 command += ",kTRUE)";
1285 else
1286 command += ")";
1287 LOG(debug1) << "command:" << command;
1288
1289 FairModule* obj = (FairModule*)gInterpreter->Calc(command);
1290 if (obj == nullptr) {
1291 LOG(error) << "ERROR: cannot create the detector module by the command: " << command;
1292 return false;
1293 }
1294 obj->SetGeometryFileName(path);
1295 fRun->AddModule(obj);
1296
1297 // cerr<<"dbModuleRev="<<dbModuleRev<<" idmr="<<mr.idmr<<" idm="<<mr.idm<<" class_name="<<typeid(f_cl).name()<<endl;
1298 return true;
1299}
1301{
1302 if (module == nullptr)
1303 return false;
1304 TString command = "new " + module->class_name + "(\"" + module->args + "\"";
1305 if (module->active)
1306 command += ",kTRUE)";
1307 else
1308 command += ")";
1309 FairModule* obj = (FairModule*)gInterpreter->Calc(command);
1310 if (obj == nullptr) {
1311 LOG(error) << "ERROR: cannot create the detector module by the command: " << command;
1312 return false;
1313 }
1314 obj->SetGeometryFileName(module->file_path);
1315 fRun->AddModule(obj);
1316 LOG(info) << "\033[0;32mAdded external detector: file_path=" << module->file_path
1317 << " class_name=" << module->class_name << " isActive=" << module->active << "\033[0m";
1318 return true;
1319}
1320
1322{
1323 TGeoManager* NewGeo = 0;
1324 TGeoVolume* volume = 0;
1325 ;
1326 TFile* f = new TFile(fileName);
1327 if (f->IsZombie() || !f->IsOpen()) {
1328 LOG(error) << "ERROR: could not open ROOT file with geometry: " << fileName;
1329 delete f;
1330 return NULL;
1331 }
1332 TList* l = f->GetListOfKeys();
1333 TKey* key;
1334 TIter next(l);
1335 TGeoNode* n = 0;
1336 // TGeoVolume* v1=0;
1337 while ((key = (TKey*)next())) {
1338 if (strcmp(key->GetClassName(), "TGeoManager") != 0) {
1339 continue;
1340 }
1341 NewGeo = (TGeoManager*)key->ReadObj();
1342 break;
1343 }
1344 if (NewGeo != 0) {
1345 NewGeo->cd();
1346 n = NewGeo->GetNode(0);
1347 f->Close();
1348 delete f;
1349 return n;
1350 } else {
1351 key = (TKey*)l->At(0); // Get the first key in the list
1352 if (key == nullptr) {
1353 LOG(error) << "ERROR: no keys found in the geometry file " << fileName;
1354 f->Close();
1355 delete f;
1356 return NULL;
1357 }
1358 volume = dynamic_cast<TGeoVolume*>(key->ReadObj());
1359 if (volume != 0) {
1360 f->Close();
1361 delete f;
1362 return volume->GetNode(0);
1363 }
1364 f->Close();
1365 delete f;
1366 return NULL;
1367 }
1368}
1369
1370bool GeoSetup::IsEqlMatrix(const char* fileName, TSQLRow* row)
1371{
1372 if (row == NULL || fileName == NULL)
1373 return false;
1374 bool res = true;
1375 try {
1376 // cerr<<"Start compare fileName:"<<fileName<<endl;
1377 TGeoNode* node = ConstructRootGeometry(fileName);
1378 if (node == NULL)
1379 return false;
1380 const Double_t* tran = node->GetMatrix()->GetTranslation(); // 3
1381 // const Double_t * sc = node->GetMatrix()->GetScale();//3
1382 const Double_t* rot = node->GetMatrix()->GetRotationMatrix(); // 9
1383 unsigned int i;
1384 for (i = 0; i < 3; i++) {
1385 double t = FieldToDouble(row->GetField(3 + i));
1386 if (tran[i] != t) {
1387 LOG(debug1) << " for i=" << i << " tran[i]=" << tran[i] << " t=" << t << endl;
1388 res = false;
1389 }
1390 }
1391 for (i = 0; i < 9; i++) {
1392 double t = FieldToDouble(row->GetField(6 + i));
1393 if (rot[i] != t) {
1394 LOG(debug1) << " for i=" << i << " rot[i]=" << rot[i] << " t=" << t << endl;
1395 res = false;
1396 }
1397 }
1398 } catch (...) {
1399 return false;
1400 }
1401 return res;
1402}
1403// load one module from the Geometry Database and add to the FairRunSim instance
1405{
1406 map<int, TString>::iterator it = m_loadedModule.find(idsm);
1407 if (it != m_loadedModule.end())
1408 return 0;
1409 // mark the module as being loaded to break possible parent_id loops in the database
1410 m_loadedModule.insert(pair<int, TString>(idsm, ""));
1411
1412 LOG(debug1) << "Start load setup_module_id=" << idsm;
1413 ostringstream stringStream;
1414 stringStream << "select "
1415 "f.module_id,f.file_name,sm.parent_id,sm.tx,sm.ty,sm.tz,r11,r12,r13,r21,r22,r23,r31,r32,r33,sm."
1416 "setup_module_tag "
1417 "from setup_module sm INNER JOIN geometry_file f ON f.file_id=sm.file_id where sm.setup_module_id="
1418 << idsm << ";";
1419
1420 TSQLResult* resQ = m_db->Query(stringStream.str().c_str());
1421 if (resQ == 0 || resQ->GetRowCount() == 0) {
1422 LOG(error) << "ERROR: no file for the setup module (" << idsm << ") was found";
1423 delete resQ;
1424 return -1;
1425 }
1426
1427 TSQLRow* row = resQ->Next();
1428 if (row == nullptr) {
1429 LOG(error) << "ERROR: no file for the setup module (" << idsm << ") was found";
1430 delete resQ;
1431 return -1;
1432 }
1433 int dbModuleIndex = FieldToInt(row->GetField(0));
1434 int idP = FieldToInt(row->GetField(2), -1);
1435 LOG(debug1) << "idP=" << idP;
1436 if (idP != -1) {
1437 int res = LoadModuleToFairRunSim(idP, fRun);
1438 if (res < 0) {
1439 delete row;
1440 delete resQ;
1441 return res;
1442 }
1443 }
1444
1445 stringStream.str("");
1446 LOG(debug1) << row->GetField(1);
1447 stringStream << GetRootPath().c_str() << (row->GetField(1) != nullptr ? row->GetField(1) : "");
1448
1449 TString mName = GetModuleType(dbModuleIndex), out = "";
1450 mName.ToUpper();
1451 bool isEnable = true;
1452 TString smTag = row->GetField(15);
1453 TString file_path = stringStream.str().c_str();
1454 smTag.ToUpper();
1455
1456 if (mName == TString("CAVE") || ((TString)stringStream.str()).EndsWith(".geo")) {
1457 map<TString, setup_module_ptr>::iterator itr = m_moduleEdit.find(smTag);
1458 if (itr != m_moduleEdit.end()) {
1459 LOG(debug1) << "detector was found";
1460 isEnable = itr->second->enable;
1461 }
1462 if (isEnable) {
1463 // a second cave replaces the top volume, so all the detectors are left outside the setup geometry
1464 bool isDuplicateCave = false;
1465 if (mName == TString("CAVE")) {
1466 TIter nextModule(fRun->GetListOfModules());
1467 while (TObject* module = nextModule())
1468 if (module->InheritsFrom("FairCave")) {
1469 isDuplicateCave = true;
1470 break;
1471 }
1472 }
1473 if (isDuplicateCave)
1474 LOG(warning) << "The cave has been already added, so the duplicate cave module with tag=" << smTag
1475 << " is skipped. Please, remove it from the setup in the Geometry Database";
1476 else {
1477 LOG(info) << "Loading module with tag=" << smTag;
1478 AddModuleToFairRunSim(dbModuleIndex, stringStream.str().c_str(), fRun);
1479 }
1480 } else
1481 LOG(info) << "\033[0;31mDisable module with tag=" << smTag << " use local settings.\033[0m";
1482 } else {
1483 double mx = 0, my = 0, mz = 0;
1484 map<TString, setup_module_ptr>::iterator itr = m_moduleEdit.find(smTag);
1485 LOG(debug1) << "detector " << dbModuleIndex;
1486 if (itr != m_moduleEdit.end()) {
1487 LOG(debug1) << "detector was found";
1488 isEnable = itr->second->enable;
1489 if (isEnable) {
1490 mx = itr->second->xMove;
1491 my = itr->second->yMove;
1492 mz = itr->second->zMove;
1493 if (itr->second->file_path.Length() > 0)
1494 file_path = itr->second->file_path;
1495 LOG(debug1) << "Move detector " << dbModuleIndex << " to x:" << mx << " to y:" << my << " to z:" << mz;
1496 }
1497 }
1498 if (isEnable && mx == 0 && my == 0 && mz == 0 && IsEqlMatrix(stringStream.str().c_str(), row)) {
1499 LOG(debug1) << "The same matrix for file=" << stringStream.str().c_str() << endl;
1500 LOG(info) << "Loading module with tag=" << smTag;
1501 AddModuleToFairRunSim(dbModuleIndex, file_path, fRun);
1502 } else if (isEnable) {
1503 TGeoManager* geom = new TGeoManager(mName, TString::Format("Geometry of the %s module", mName.Data()));
1504 LOG(debug1) << "import file" << file_path << endl;
1505 TFile* f = new TFile(file_path);
1506 if (f->IsZombie() || !f->IsOpen()) {
1507 LOG(error) << "ERROR: could not open ROOT file with the module geometry: " << file_path;
1508 delete f;
1509 delete geom;
1510 delete row;
1511 delete resQ;
1512 return -1;
1513 }
1514 TGeoVolume* root_volume = GetRootVolume(f);
1515 if (root_volume == nullptr || root_volume->GetNode(0) == nullptr) {
1516 LOG(error) << "ERROR: no geometry volume found in the file: " << file_path;
1517 f->Close();
1518 delete f;
1519 delete geom;
1520 delete row;
1521 delete resQ;
1522 return -1;
1523 }
1524 double tx = FieldToDouble(row->GetField(3)) + mx;
1525 double ty = FieldToDouble(row->GetField(4)) + my;
1526 double tz = FieldToDouble(row->GetField(5)) + mz;
1527 TGeoRotation rotM;
1528 TGeoGenTrans* newMatrix = new TGeoGenTrans(tx, ty, tz, 1, 1, 1, &rotM);
1529 if (strcmp(root_volume->GetNode(0)->ClassName(), "TGeoNodeMatrix") == 0) {
1530 TGeoNodeMatrix* v = (TGeoNodeMatrix*)root_volume->GetNode(0);
1531 v->SetMatrix(newMatrix);
1532 }
1533
1534 out = GetTmpPath() + GetModuleName(GetModuleId(dbModuleIndex)) + ".root";
1535 root_volume->Export(out.Data());
1536 LOG(info) << "Loading module with tag=" << smTag;
1537 AddModuleToFairRunSim(dbModuleIndex, out.Data(), fRun);
1538 LOG(debug1) << "Exporting geometry to ROOT file: " << out;
1539
1540 delete geom;
1541 f->Close();
1542 delete f;
1543 } else
1544 LOG(info) << "\033[0;31mDisable module with tag=" << smTag << " use local settings.\033[0m";
1545 }
1546 m_loadedModule[idsm] = out;
1547
1548 delete row;
1549 delete resQ;
1550 return 0;
1551}
1552
1553// fill table with modules (m_modules_table) from the Geometry Database
1555{
1556 TSQLResult* resQ = m_db->Query("select module_id,module_name from module;");
1557 if (resQ == nullptr) {
1558 LOG(error) << "ERROR: SQL query was failed. Please, check connection to the Geometry Database and "
1559 "DBL_FILE_PATH variable is correct";
1560 return -1;
1561 }
1562 if (resQ->GetRowCount() == 0) {
1563 LOG(error) << "ERROR: no modules in the Geometry Database";
1564 delete resQ;
1565 return -2;
1566 }
1567
1568 TSQLRow* row;
1569 while ((row = resQ->Next()) != 0) {
1570 int id = FieldToInt(row->GetField(0));
1571 TString name(row->GetField(1));
1572 m_modules_table.insert(make_pair(id, name));
1573 delete row;
1574 }
1575
1576 delete resQ;
1577 return 0;
1578}
1579
1580// fill table with module revisions (m_modules_revision_table) from the Geometry Database
1582{
1583 TSQLResult* resQ = m_db->Query("select module_class_id,mc.module_id,class_name,revision,active,object_name from "
1584 "module_class as mc INNER JOIN module as m ON mc.module_id=m.module_id;");
1585 if (resQ == nullptr) {
1586 LOG(error) << "ERROR: SQL query was failed. Please, check connection to the Geometry Database and "
1587 "DBL_FILE_PATH variable is correct";
1588 return -1;
1589 }
1590 if (resQ->GetRowCount() == 0) {
1591 LOG(error) << "ERROR: no module revisions in the geometry database";
1592 delete resQ;
1593 return -2;
1594 }
1595
1596 TSQLRow* row;
1597 while ((row = resQ->Next()) != 0) {
1598 module_r_ptr mr = new module_r();
1599 mr->idmr = FieldToInt(row->GetField(0));
1600 mr->idm = FieldToInt(row->GetField(1));
1601 mr->class_name = row->GetField(2);
1602 mr->rev = FieldToInt(row->GetField(3));
1603 if (FieldToInt(row->GetField(4)) == 0)
1604 mr->active = false;
1605 else
1606 mr->active = true;
1607 mr->args = row->GetField(5);
1608
1609 m_modules_revision_table.insert(make_pair(mr->idmr, mr));
1610 delete row;
1611 }
1612
1613 delete resQ;
1614 return 0;
1615}
bool ichar_equals(char a, char b)
Definition GeoSetup.cxx:36
static pid_t gWritableDbPid
Definition GeoSetup.cxx:284
static int FieldToInt(const char *field, int defaultValue=0)
Definition GeoSetup.cxx:43
static void RemoveWritableDbDir()
Definition GeoSetup.cxx:287
static uint64_t FieldToUInt64(const char *field, uint64_t defaultValue=0)
Definition GeoSetup.cxx:52
static string SqlEscape(string_view value)
Definition GeoSetup.cxx:83
static void RemoveAssemblyShapes(TGeoManager *geoManager)
Definition GeoSetup.cxx:492
static double FieldToDouble(const char *field, double defaultValue=0.)
Definition GeoSetup.cxx:61
static string gWritableDbDir
Definition GeoSetup.cxx:283
static bool IsSafeTag(const string &tag)
Definition GeoSetup.cxx:71
__m128 v
Definition P4_F32vec4.h:1
int i
Definition P4_F32vec4.h:22
double Double_t
constexpr Bool_t kTRUE
R__EXTERN TGeoManager * gGeoManager
#define gInterpreter
Bool_t R_ISDIR(Int_t mode)
R__EXTERN TSystem * gSystem
void * XMLNodePointer_t
void * XMLDocPointer_t
void * XMLAttrPointer_t
void SetFileName(const char *map_file_name)
Set field map file path.
Definition BmnFieldMap.h:65
void SetScale(Double_t factor)
Set a global field scaling factor.
Definition BmnFieldMap.h:55
Field Map does not have any symmetries w.r.t coordinate axises.
TString & GetTmpPath()
int GetModuleId(int dbModuleRev)
TGeoNode * ConstructRootGeometry(const char *fileName)
string GetParameterFile(string_view detector_name)
Get path to parameter file for the given detector name of the current setup.
Definition GeoSetup.cxx:933
string m_setupTag
Definition GeoSetup.h:124
bool OpenLocalGeoDatabase()
Definition GeoSetup.cxx:459
string ExpandDbFilePath()
int m_sid
Definition GeoSetup.h:120
TString GetModuleName(int dbModuleUndex)
int LoadModuleToFairRunSim(int idsm, FairRunSim *fRun)
int PutModules()
TString GetTmpFileName(const char *baseName)
Definition GeoSetup.cxx:97
int LoadSetupToGeoManager(string_view setup_tag)
Load selected geometry setup from the Local Geometry Database and create gGeoManager instance.
Definition GeoSetup.cxx:512
string GetLocalDbPath()
bool LoadLocalSettings(const char *fileName)
string GetMaterialFile()
Get the material file of the current setup, which defines the media of the setup geometry.
Definition GeoSetup.cxx:985
string GetRootPath()
map< int, TString > m_modules_table
Definition GeoSetup.h:107
map< TString, setup_module_ptr > m_moduleEdit
Definition GeoSetup.h:110
std::pair< int, uint64_t > CheckTagOnServer(string_view setup_tag, const char *url=GEO_SERVER_HOST)
Definition GeoSetup.cxx:178
TGeoVolume * GetRootVolume(TFile *f)
FairField * m_field
Definition GeoSetup.h:116
int installLocalDB(string_view setup_tag, const char *url=GEO_SERVER_HOST)
Definition GeoSetup.cxx:331
unsigned long int GetServerRevision(const char *url=GEO_SERVER_HOST)
Definition GeoSetup.cxx:102
vector< module_r_ptr > m_moduleAdd
Definition GeoSetup.h:111
map< int, module_r_ptr > m_modules_revision_table
Definition GeoSetup.h:108
TSQLServer * m_db
Definition GeoSetup.h:114
TString GetModuleType(int dbModuleRev)
void CloseDB()
Definition GeoSetup.cxx:441
int PutModuleRevisions()
TString PrepareWritableDbDir()
Definition GeoSetup.cxx:300
int m_fid
Definition GeoSetup.h:118
module_r_ptr GetModuleRevision(int dbModuleRev)
static bool exists_file(const char *name)
Definition GeoSetup.cxx:31
static bool IsWritableDir(const char *path)
Definition GeoSetup.cxx:276
map< int, TString > m_loadedModule
Definition GeoSetup.h:109
int GetModuleIndex(TString &name)
TString m_tmpFolder
Definition GeoSetup.h:122
FairField * GetMagneticField(double scale=-1)
Get magnetic field of the current setup geometry.
Definition GeoSetup.cxx:877
bool IsEqlMatrix(const char *fileName, TSQLRow *row)
~GeoSetup()
Destructor method.
Definition GeoSetup.cxx:453
unsigned long int GetLocalRevision(TString &localDbPath)
Definition GeoSetup.cxx:248
std::pair< int, string > GetTagName4PatternLocal(string_view pattern_tag, TString &localDbPath)
Definition GeoSetup.cxx:224
bool AddModuleToFairRunSim(module_r_ptr module, FairRunSim *fRun)
std::pair< int, string > GetTagName4PatternServer(string_view pattern_tag, const char *url=GEO_SERVER_HOST)
Definition GeoSetup.cxx:137
string GetLastApprovedSetupTag(string_view tag_prefix)
Get tag for the last approved setup corresponding to the pattern.
Definition GeoSetup.cxx:122
string m_materialFile
Definition GeoSetup.h:126
int LoadSetupToFairRunSim(string_view setupTag, const char *localSettings=nullptr)
Load selected geometry setup from the Local or Central (defined by url) Geometry Database and add it ...
Definition GeoSetup.cxx:643
TList * GetListOfKeys() const override
virtual Bool_t IsOpen() const
TObjArray * GetListOfVolumes() const
virtual Bool_t cd(const char *path="")
TGeoNode * GetNode(Int_t level) const
TObjArray * GetListOfShapes() const
virtual const Double_t * GetTranslation() const=0
virtual const Double_t * GetRotationMatrix() const=0
TGeoVolume * GetVolume() const
Int_t GetNdaughters() const
TGeoNode * GetDaughter(Int_t ind) const
virtual TGeoMatrix * GetMatrix() const=0
TGeoNode * GetNode(const char *name) const
Int_t Export(const char *filename, const char *name="", Option_t *option="")
TObject * At(Int_t idx) const override
virtual void Compress()
TObject * Remove(TObject *obj) override
virtual const char * ClassName() const
R__ALWAYS_INLINE Bool_t IsZombie() const
virtual Int_t GetRowCount() const
virtual TSQLRow * Next()=0
virtual const char * GetField(Int_t field)=0
virtual Bool_t IsConnected() const
TSQLResult * Query(const char *sql) final
Ssiz_t Length() const
int CompareTo(const char *cs, ECaseCompare cmp=kExact) const
Bool_t EndsWith(const char *pat, ECaseCompare cmp=kExact) const
TSubString Strip(EStripType s=kTrailing, char c=' ') const
Double_t Atof() const
const char * Data() const
void ToUpper()
Bool_t BeginsWith(const char *s, ECaseCompare cmp=kExact) const
Bool_t IsNull() const
static TString Format(const char *fmt,...)
XMLNodePointer_t GetChild(XMLNodePointer_t xmlnode, Bool_t realnode=kTRUE)
void FreeDoc(XMLDocPointer_t xmldoc)
XMLNodePointer_t DocGetRootElement(XMLDocPointer_t xmldoc)
XMLAttrPointer_t GetNextAttr(XMLAttrPointer_t xmlattr)
const char * GetAttrName(XMLAttrPointer_t xmlattr)
XMLAttrPointer_t GetFirstAttr(XMLNodePointer_t xmlnode)
const char * GetNodeName(XMLNodePointer_t xmlnode)
XMLDocPointer_t ParseFile(const char *filename, Int_t maxbuf=100000)
const char * GetAttrValue(XMLAttrPointer_t xmlattr)
XMLNodePointer_t GetNext(XMLNodePointer_t xmlnode, Bool_t realnode=kTRUE)
struct SETUPMODULE * setup_module_ptr
struct MODULEREVISION * module_r_ptr
const char *const GEO_SERVER_HOST
struct SETUPMODULE setup_module
struct MODULEREVISION module_r
*brief user defined string literal for JSON values *sa std::size_t n
Definition json.hpp:20362
Long64_t fSize
TString class_name
Definition GeoSetup.h:29
TString args
Definition GeoSetup.h:32
TString file_path
Definition GeoSetup.h:33
TString type
Definition GeoSetup.h:21
double zMove
Definition GeoSetup.h:22
TString file_path
Definition GeoSetup.h:24
double xMove
Definition GeoSetup.h:22
double yMove
Definition GeoSetup.h:22
bool enable
Definition GeoSetup.h:23
TString fUser