Hall-D Software  alpha
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
DApplication.cc
Go to the documentation of this file.
1 // $Id$
2 //
3 // File: DApplication.cc
4 // Created: Mon Jul 3 21:46:01 EDT 2006
5 // Creator: davidl (on Darwin Harriet.local 8.6.0 powerpc)
6 //
7 
8 #include <string>
9 using std::string;
10 #include <JANA/JVersion.h>
11 
12 #include <pthread.h>
13 #include <iostream>
14 #include <fstream>
15 #include <unistd.h>
16 #include <sys/types.h>
17 #include <sys/stat.h>
18 
19 
20 #include "DApplication.h"
33 #include <HDGEOMETRY/DRootGeom.h>
34 #include "DFactoryGenerator.h"
35 
36 #include "DANARootErrorHandler.h"
37 #include "DStatusBits.h"
38 
39 
40 //---------------------------------
41 // DApplication (Constructor)
42 //---------------------------------
43 DApplication::DApplication(int narg, char* argv[]):JApplication(narg, argv)
44 {
45  pthread_mutex_init(&mutex, NULL);
46 
47  //disable inherently (and horrorifically)-unsafe registration of EVERY TObject with the global TObjectTable //multithreading!!
48  //simply setting/checking a bool is not thread-safe due to cache non-coherence and operation re-shuffling by the compiler
49  TObject::SetObjectStat(kFALSE);
50  //Similar: This adds functions to the global gROOT. We don't want this, because different threads tend to have their own functions with the same name.
51  TF1::DefaultAddToGlobalList(kFALSE);
52 
53  // Add plugin paths to Hall-D specific binary directories
54  const char *bms_osname = getenv("BMS_OSNAME");
55  string sbms_osname(bms_osname==NULL ? "":bms_osname);
56 
57  if(const char *ptr = getenv("DANA_PLUGIN_PATH")){
58  AddPluginPath(string(ptr));
59  }
60  if(const char *ptr = getenv("HALLD_MY")){
61  AddPluginPath(string(ptr) + "/" + sbms_osname + "/plugins"); // SBMS
62  AddPluginPath(string(ptr) + "/lib/" + sbms_osname); // BMS
63  }
64  if(const char *ptr = getenv("HALLD_RECON_HOME")){
65  AddPluginPath(string(ptr) + "/" + sbms_osname + "/plugins"); // SBMS
66  AddPluginPath(string(ptr) + "/lib/" + sbms_osname); // BMS
67  }
68 
69  // Initialize pointers to NULL. Objects will be instantiated as needed
70  bfield = NULL;
71  lorentz_def = NULL;
72  RootGeom = NULL;
73  dircLut = NULL;
74 
75  // Since we defer reading in some tables until they are requested
76  // (likely while processing the first event) that time gets counted
77  // against the thread as being non-reponsive. The default timeout
78  // of 8 seconds is therefore too small. Change it to 30 here,
79  // unless the user has set it explicitly on the command line.
80  map<string,string> parmap;
81  JParameterManager *pm = GetJParameterManager();
82  pm->GetParameters(parmap, "THREAD_TIMEOUT");
83  if (parmap.empty()) {
84  pm->SetParameter("THREAD_TIMEOUT", "30 seconds");
85  }
86 
87  // Optionally copy SQLite CCDB file to local disk
89 
90  /// Add DEventSourceHDDMGenerator and
91  /// DFactoryGenerator, which adds the default
92  /// list of Hall-D factories
93  bool HDDM_ENABLE = true;
94  pm->SetDefaultParameter("HDDM:ENABLE", HDDM_ENABLE, "Enable the HDDM source readers. If set to 0, input files are assumed to never be of an HDDM format.");
95  if(HDDM_ENABLE){
97  AddEventSourceGenerator(event_source_generator);
98  AddEventSourceGenerator(new DEventSourceRESTGenerator());
99  AddEventSourceGenerator(new JEventSourceGenerator_EVIOpp());
100  AddEventSourceGenerator(new JEventSourceGenerator_EVIO());
101  AddEventSourceGenerator(new DEventSourceEventStoreGenerator());
102  }
104  AddFactoryGenerator(factory_generator);
105 
106  if(JVersion::minor<5)Init();
107 
108 }
109 
110 //---------------------------------
111 // Init
112 //---------------------------------
113 jerror_t DApplication::Init(void)
114 {
115  this->JApplication::Init();
116 
117  // Install our own error handler for ROOT message
118  int ROOT_ERROR_LEVEL_SUPRESS = 10000;
119  GetJParameterManager()->SetDefaultParameter("ROOT_ERROR_LEVEL_SUPRESS", ROOT_ERROR_LEVEL_SUPRESS);
120  InitDANARootErrorHandler(ROOT_ERROR_LEVEL_SUPRESS);
121 
122  // Define base set of status bits
124 
125  // Only check SSE capabilities if we're going to use the variables
126  // below so as to avoid compiler warnings.
127 #if USE_SIMD || USE_SSE2 || USE_SSE3
128 
129  // Check if running on a cpu that supports the instruction set
130  // extensions that were assumed when this application was built
131  unsigned int cpeinfo;
132  unsigned int cpsse3;
133 // unsigned int amdinfo;
134  asm("mov $0x01, %%eax\ncpuid\n"
135  : "=d" (cpeinfo), "=c" (cpsse3)
136  );
137 // asm("mov $0x80000001, %%eax\ncpuid\n"
138 // : "=d" (amdinfo)
139 // );
140 //
141 // int mmx = ((cpeinfo >> 23) & 0x1 );
142 // int sse = ((cpeinfo >> 25) & 0x1 );
143 // int sse2 = ((cpeinfo >> 26) & 0x1 );
144 // int sse3 = ((cpsse3 ) & 0x1 );
145 // int ssse3 = ((cpsse3 >> 9) & 0x1 );
146 // int sse4_1 = ((cpsse3 >> 19) & 0x1 );
147 // int sse4_2 = ((cpsse3 >> 20) & 0x1 );
148 // int sse4a = ((amdinfo >> 6) & 0x1 );
149 #endif // USE_SIMD || USE_SSE2 || USE_SSE3
150 
151 #if USE_SIMD
152  int sse = ((cpeinfo >> 25) & 0x1 );
153  if (sse == 0) {
154  jerr<<"DApplication::Init error - application was built"
155  <<" to run only on machines" << endl
156  <<"supporting the SSE processor extensions."
157  <<" Please run on a processor that" << endl
158  <<"supports SSE, or rebuild with DISABLE_SIMD=yes."
159  << endl;
160  return UNRECOVERABLE_ERROR;
161  }
162 #endif
163 
164 #if USE_SSE2
165  int sse2 = ((cpeinfo >> 26) & 0x1 );
166  if (sse2 == 0) {
167  jerr<<"DApplication::Init error - application was built"
168  <<" to run only on machines" << endl
169  <<"supporting the SSE2 processor extensions."
170  <<" Please run on a processor that" << endl
171  <<"supports SSE2, or rebuild with DISABLE_SSE2=yes."
172  << endl;
173  return UNRECOVERABLE_ERROR;
174  }
175 #endif
176 
177 #if USE_SSE3
178  int sse3 = ((cpsse3 ) & 0x1 );
179  if (sse3 == 0) {
180  jerr<<"DApplication::Init error - application was built"
181  <<" to run only on machines" << endl
182  <<"supporting the SSE3 processor extensions."
183  <<" Please run on a processor that" << endl
184  <<"supports SSE3, or rebuild with DISABLE_SSE3=yes."
185  << endl;
186  return UNRECOVERABLE_ERROR;
187  }
188 #endif
189 
190  return NOERROR;
191 }
192 
193 //---------------------------------
194 // ~DApplication (Destructor)
195 //---------------------------------
197 {
198  if(bfield) delete bfield;
199  if(lorentz_def) delete lorentz_def;
200 
201  // As of JANA 0.6.3 and later, the following are
202  // automatically deleted when ~JApplication is called.
203  // Freeing them a second time causes seg. faults. so
204  // we disable that here. 2/14/2011 DL
205  //if(event_source_generator) delete event_source_generator;
206  //if(factory_generator) delete factory_generator;
207  //if(RootGeom) delete RootGeom;
208  //for(unsigned int i=0; i<geometries.size(); i++) delete geometries[i];
209 
210  Lock();
211  for (unsigned int i=0;i<geometries.size();i++)delete geometries[i];
212  geometries.clear();
213  Unlock();
214 }
215 
216 //---------------------------------
217 // GetDGeometry
218 //---------------------------------
219 DGeometry* DApplication::GetDGeometry(unsigned int run_number)
220 {
221  /// Get the DGeometry object for the specified run number.
222  /// The DGeometry class is Hall-D specific. It uses the
223  /// JGeometry class from JANA to access values in the HDDS
224  /// XML files. However, it supplies some useful and more
225  /// user friendly methods for getting at some of the values.
226  ///
227  /// This will first look for the DGeometry object in a list
228  /// kept internal to DApplication and return a pointer to the
229  /// object if found there. If it is not found there, then
230  /// a new DGeometry object will be created and added to the
231  /// internal list before returning a pointer to it.
232  ///
233  /// Note that since this method can change internal data
234  /// members, a mutex is locked to ensure integrity. This
235  /// means that it is <b>NOT</b> efficient to call this
236  /// method for every event. The pointer should be obtained
237  /// in a brun() method and kept in a local variable if
238  /// needed outside of brun().
239 
240  // At this point in time, only simulation exists with geometry coming
241  // from a JGeometryXML object. The run range for these objects is
242  // always set to include only the run number requested so if multiple
243  // places in the code ask for different run numbers (as happens) a
244  // second DGeometry object is created unecessarily. Here, we look to
245  // see if a sole DGeometry object already exists and if so, if it is
246  // built on a JGeometryFile object. If so, simply return it under the
247  // assumption we are still doing development with simulated data and
248  // a single set of geometry files.
249  Lock();
250  if(geometries.size()==1 && string("JGeometryXML")==geometries[0]->GetJGeometry()->className()){
251  Unlock();
252  return geometries[0];
253  }
254  Unlock();
255 
256  // First, get the JGeometry object using our JApplication
257  // base class. Then, use that to find the correct DGeometry
258  // object if it exists.
259  JGeometry *jgeom = GetJGeometry(run_number);
260  if(!jgeom){
261  _DBG_<<"ERROR: Unable get geometry for run "<<run_number<<"!"<<endl;
262  _DBG_<<"Make sure you JANA_GEOMETRY_URL environment variable is set."<<endl;
263  _DBG_<<"It should be set to something like:"<<endl;
264  _DBG_<<endl;
265  _DBG_<<" xmlfile://${HALLD_RECON_HOME}/src/programs/Simulation/hdds/main_HDDS.xml"<<endl;
266  _DBG_<<endl;
267  _DBG_<<"Exiting now."<<endl;
268  Quit();
269  exit(-1);
270  return NULL;
271  }
272 
273 
274  Lock();
275 
276  for(unsigned int i=0; i<geometries.size(); i++){
277  if(geometries[i]->GetJGeometry() == jgeom){
278  DGeometry *dgeom = geometries[i];
279  Unlock();
280  return dgeom;
281  }
282  }
283 
284  jout<<"Creating DGeometry:"<<endl;
285  jout<<" Run requested:"<<jgeom->GetRunRequested()<<" found:"<<jgeom->GetRunFound()<<endl;
286  jout<<" Run validity range: "<<jgeom->GetRunMin()<<"-"<<jgeom->GetRunMax()<<endl;
287  jout<<" URL=\""<<jgeom->GetURL()<<"\""<<" context=\""<<jgeom->GetContext()<<"\""<<endl;
288  jout<<" Type=\""<<jgeom->className()<<"\""<<endl;
289 
290  // Couldn't find a DGeometry object that uses this JGeometry object.
291  // Create one and add it to the list.
292  DGeometry *dgeom = new DGeometry(jgeom, this, run_number);
293  geometries.push_back(dgeom);
294 
295  Unlock();
296 
297  return dgeom;
298 }
299 
300 
301 //---------------------------------
302 // GetBfield
303 //---------------------------------
305 {
306  const char *ccdb_help =
307  " \n"
308  " Could not load the solenoid field map from the CCDB!\n"
309  " Please specify the solenoid field map to use on the command line, e.g.:\n"
310  " \n"
311  " -PBFIELD_MAP=Magnets/Solenoid/solenoid_1200A_poisson_20140520\n"
312  " or\n"
313  " -PBFIELD_TYPE=NoField\n";
314 
315  pthread_mutex_lock(&mutex);
316 
317  // If field map already exists, return it immediately
318  if(bfield){
319  pthread_mutex_unlock(&mutex);
320  return bfield;
321  }
322 
323  // Create magnetic field object for use by everyone
324  // Allow a trivial homogeneous map to be used if
325  // specified on the command line
326  string bfield_type = "FineMesh";
327  string bfield_map = "";
328  GetJParameterManager()->SetDefaultParameter("BFIELD_TYPE", bfield_type);
329  if( GetJParameterManager()->Exists("BFIELD_MAP") ) {
330  bfield_map = GetJParameterManager()->GetParameter("BFIELD_MAP")->GetValue();
331  }
332  if(bfield_type=="CalibDB"|| bfield_type=="FineMesh"){
333  // if the magnetic field map got passed in on the command line, then use that value instead of the CCDB values
334  if( bfield_map != "" ) {
335  bfield = new DMagneticFieldMapFineMesh(this,run_number,bfield_map);
336  } else {
337  // otherwise, we load some default map
338  // see if we can load the name of the magnetic field map to use from the calib DB
339  JCalibration *jcalib = GetJCalibration(run_number);
340  map<string,string> bfield_map_name;
341  if(jcalib->GetCalib("/Magnets/Solenoid/solenoid_map", bfield_map_name)) {
342  // if we can't find information in the CCDB, then quit with an error message
343  jerr << ccdb_help << endl;
344  exit(-1);
345  } else {
346  if( bfield_map_name.find("map_name") != bfield_map_name.end() ) {
347  if( bfield_map_name["map_name"] == "NoField" ) // special case for no magnetic field
348  bfield = new DMagneticFieldMapNoField(this);
349  else
350  bfield = new DMagneticFieldMapFineMesh(this,run_number,bfield_map_name["map_name"]); // pass along the name of the magnetic field map to load
351  } else {
352  // if we can't find information in the CCDB, then quit with an error message
353  jerr << ccdb_help << endl;
354  exit(-1);
355  }
356  }
357  }
358  string subclass = "<none>";
359  if(dynamic_cast<DMagneticFieldMapFineMesh*>(bfield)) subclass = "DMagneticFieldMapFineMesh";
360  if(dynamic_cast<DMagneticFieldMapNoField*>(bfield)) subclass = "DMagneticFieldMapNoField";
361  jout<<"Created Magnetic field map of type " << subclass <<endl;
362  }else if(bfield_type=="Const"){
363  bfield = new DMagneticFieldMapConst(0.0, 0.0, 1.9);
364  jout<<"Created Magnetic field map of type DMagneticFieldMapConst."<<endl;
365  //}else if(bfield_type=="Spoiled"){
366  // bfield = new DMagneticFieldMapSpoiled(this);
367  // jout<<"Created Magnetic field map of type DMagneticFieldMapSpoiled."<<endl;
368  //}else if(bfield_type=="Parameterized"){
369  // bfield = new DMagneticFieldMapParameterized(this);
370  // jout<<"Created Magnetic field map of type DMagneticFieldMapParameterized."<<endl;
371  //}
372  }else if (bfield_type=="NoField"){
373  bfield = new DMagneticFieldMapNoField(this);
374  jout << "Created Magnetic field map with B=(0,0,0) everywhere." <<endl;
375  }else{
376  _DBG_<<" Unknown DMagneticFieldMap subclass \"DMagneticFieldMap"<<bfield_type<<"\" !!"<<endl;
377  exit(-1);
378  }
379 
380  pthread_mutex_unlock(&mutex);
381 
382  return bfield;
383 }
384 
385 //---------------------------------
386 // GetLorentzDeflections
387 //---------------------------------
389 {
390  pthread_mutex_lock(&mutex);
391 
392  // If field map already exists, return it immediately
393  if(lorentz_def){
394  pthread_mutex_unlock(&mutex);
395  return lorentz_def;
396  }
397 
398  // Create Lorentz deflection object
399  lorentz_def= new DLorentzMapCalibDB(this, run_number);
400 
401  pthread_mutex_unlock(&mutex);
402 
403  return lorentz_def;
404 }
405 
406 //---------------------------------
407 // GetRootGeom
408 //---------------------------------
409 DRootGeom* DApplication::GetRootGeom(unsigned int run_number)
410 {
411  pthread_mutex_lock(&mutex);
412 
413  // If field map already exists, return it immediately
414  if(RootGeom){
415  pthread_mutex_unlock(&mutex);
416  return RootGeom;
417  }
418 
419  // Create map of material properties
420  //material = new DMaterialMapCalibDB(this);
421  RootGeom = new DRootGeom(this, run_number);
422 
423  pthread_mutex_unlock(&mutex);
424 
425  return RootGeom;
426 }
427 
428 //---------------------------------
429 // CopySQLiteToLocalDisk
430 //---------------------------------
432 {
433  // Check if parameters are set and consistent
434  JParameterManager *pm = GetJParameterManager();
435  if(! pm->Exists("SQLITE_TO_LOCAL") ) return;
436 
437  string tmp;
438  pm->SetDefaultParameter("SQLITE_TO_LOCAL", tmp);
439 
440  string JANA_CALIB_URL;
441  if( pm->Exists("JANA_CALIB_URL" ) ){
442  pm->GetParameter("JANA_CALIB_URL", JANA_CALIB_URL);
443  }else{
444  auto url_env = getenv("JANA_CALIB_URL");
445  if( url_env != NULL) JANA_CALIB_URL = url_env;
446  }
447  if( JANA_CALIB_URL.empty() ) return;
448 
449  if( JANA_CALIB_URL.find("sqlite://") != 0 ){
450  jout << "WARNING: SQLITE_TO_LOCAL specified but JANA_CALIB_URL does not specify a" << endl;
451  jout << " SQLite source. SQLITE_TO_LOCAL will be ignored." << endl;
452  return;
453  }
454 
455  // Get destination and source file names
456  string dest;
457  pm->GetParameter("SQLITE_TO_LOCAL", dest);
458  string src = JANA_CALIB_URL.substr(10);
459 
460  // Check if source exists
461  if( access(src.c_str(), R_OK) == -1 ){
462  jout << "WARNING: SQLITE_TO_LOCAL specified but sqlite file specified in JANA_CALIB_URL:" << endl;
463  jout << " " << src << " does not exist. SQLITE_TO_LOCAL will be ignored." << endl;
464  return;
465  }
466 
467  // Check if destination exists
468  bool copy_sqlite_file = true;
469  if( access(dest.c_str(), R_OK) != -1 ){
470 
471  // Check if file sizes are identical
472  ifstream ifsrc(src.c_str());
473  ifsrc.seekg(0, ifsrc.end);
474  auto size_src = ifsrc.tellg();
475  ifsrc.close();
476  ifstream ifdest(dest.c_str());
477  ifdest.seekg(0, ifdest.end);
478  auto size_dest = ifdest.tellg();
479  ifdest.close();
480 
481  if( size_src == size_dest ){
482 
483  // File sizes are identical. Check if source is also older than dest.
484  struct stat src_result;
485  struct stat dest_result;
486  stat(src.c_str(), &src_result);
487  stat(dest.c_str(), &dest_result);
488  if( src_result.st_mtime < dest_result.st_mtime ){
489  jout << "Modification time of " << src << " is older than " << dest << endl;
490  jout << "so file will not be copied" << endl;
491  copy_sqlite_file = false;
492  }
493  }
494  }
495 
496  // Copy sqlite file to specified location if needed
497  if( copy_sqlite_file ){
498  jout << "Copying " << src << " -> " << dest << endl;
499  unlink(dest.c_str());
500  std::ifstream ifs(src.c_str(), std::ios::binary);
501  std::ofstream ofs(dest.c_str(), std::ios::binary);
502  ofs << ifs.rdbuf();
503  }
504 
505  // Overwrite the JANA_CALIB_URL config. parameter with the new destination
506  JANA_CALIB_URL = "sqlite:///" + dest;
507  jout << "Overwriting JANA_CALIB_URL with: " << JANA_CALIB_URL << endl;
508  pm->SetParameter("JANA_CALIB_URL", JANA_CALIB_URL);
509 }
510 
511 //---------------------------------
512 // GetDIRCLut
513 //---------------------------------
514 DDIRCLutReader* DApplication::GetDIRCLut(unsigned int run_number)
515 {
516  pthread_mutex_lock(&mutex);
517 
518  // If DIRC LUT already exists, return it immediately
519  if(dircLut){
520  pthread_mutex_unlock(&mutex);
521  return dircLut;
522  }
523 
524  // create new DIRC LUT
525  dircLut = new DDIRCLutReader(this, run_number);
526 
527  pthread_mutex_unlock(&mutex);
528 
529  return dircLut;
530 }
DApplication(int narg, char *argv[])
The DApplication class extends the JApplication class by adding the default event source generators a...
Definition: DApplication.cc:43
DLorentzDeflections * lorentz_def
Definition: DApplication.h:67
char string[256]
DMagneticFieldMap * GetBfield(unsigned int run_number=1)
DDIRCLutReader * dircLut
Definition: DApplication.h:72
DLorentzDeflections * GetLorentzDeflections(unsigned int run_number=1)
static int ROOT_ERROR_LEVEL_SUPRESS
DRootGeom * RootGeom
Definition: DApplication.h:70
pthread_mutex_t mutex
Definition: DApplication.h:74
void CopySQLiteToLocalDisk(void)
DRootGeom * GetRootGeom(unsigned int run_number)
virtual ~DApplication()
DMagneticFieldMap * bfield
Definition: DApplication.h:66
JEventSourceGenerator * event_source_generator
Definition: DApplication.h:68
DGeometry * GetDGeometry(unsigned int run_number)
vector< DGeometry * > geometries
Definition: DApplication.h:71
#define _DBG_
Definition: HDEVIO.h:12
JFactoryGenerator * factory_generator
Definition: DApplication.h:69
jerror_t Init(void)
DDIRCLutReader * GetDIRCLut(unsigned int run_number)
static void SetStatusBitDescriptions(jana::JApplication *japp)
Definition: DStatusBits.h:60
void InitDANARootErrorHandler(int my_ROOT_ERROR_LEVEL_SUPRESS)
virtual const char * className(void)
Definition: DGeometry.h:39
Implements JEventSourceGenerator for REST files.