Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 10:17:31

0001 
0002 
0003 // Copyright 2007-2025, Jefferson Science Associates, LLC.
0004 // Subject to the terms in the LICENSE file found in the top-level directory.
0005 // Author: David Lawrence
0006 
0007 #include <JANA/JLogger.h>
0008 #include "JCalibration.h"
0009 
0010 #include <cstring>
0011 #include <dirent.h>
0012 #include <fstream>
0013 #include <iostream>
0014 #include <string>
0015 #include <sys/stat.h>
0016 #include <unistd.h>
0017 
0018 using namespace std;
0019 
0020 
0021 
0022 //---------------------------------
0023 // JCalibration    (Constructor)
0024 //---------------------------------
0025 JCalibration::JCalibration(string url, int32_t run, string context)
0026 {
0027     this->url = url;
0028     this->run_number = run;
0029     this->context = context;
0030 
0031     retrieved_event_boundaries = false;
0032 
0033     pthread_mutex_init(&accesses_mutex, NULL);
0034     pthread_mutex_init(&stored_mutex, NULL);
0035     pthread_mutex_init(&boundaries_mutex, NULL);
0036 }
0037 
0038 //---------------------------------
0039 // ~JCalibration    (Destructor)
0040 //---------------------------------
0041 JCalibration::~JCalibration()
0042 {
0043     // Here we need to delete any data being kept in the "stored" map.
0044     // This is difficult since the pointers are kept as void* types
0045     // so we can't call delete without type casting them back into the
0046     // appropriate pointer type. Note that everywhere but here, the
0047     // stored vector is accessed through a templated method so the caller
0048     // provides the type information.
0049     //
0050     // The best we can do here is to check the typeid name against the list
0051     // of containers based on primitive types (+string) to see if we
0052     // can match it that way. We do this by calling the TryDelete templated
0053     // method which will build each of the 4 container types based on
0054     // the primitive type used for the template specialization parameter.
0055 
0056     // Loop over stored data containers
0057     map<pair<string,string>, void*>::iterator iter;
0058     for(iter=stored.begin(); iter!=stored.end(); iter++){
0059 
0060                 if(TryDelete<         double >(iter));
0061         else    if(TryDelete<         float  >(iter));
0062         else    if(TryDelete<         int    >(iter));
0063         else    if(TryDelete<         long   >(iter));
0064         else    if(TryDelete<         short  >(iter));
0065         else    if(TryDelete<         char   >(iter));
0066         else    if(TryDelete<unsigned int    >(iter));
0067         else    if(TryDelete<unsigned long   >(iter));
0068         else    if(TryDelete<unsigned short  >(iter));
0069         else    if(TryDelete<unsigned char   >(iter));
0070         else    if(TryDelete<         string >(iter));
0071         else{
0072             LOG<<"Unable to delete calibration constants of type: "<<iter->first.second<<LOG_END;
0073             LOG<<"namepath: "<<iter->first.first<<LOG_END;
0074             LOG<<LOG_END;
0075         }
0076     }
0077 }
0078 
0079 //---------------------------------
0080 // PutCalib
0081 //---------------------------------
0082 bool JCalibration::PutCalib(string /*namepath*/, int32_t /*run_min*/, int32_t /*run_max*/, uint64_t /*event_min*/, uint64_t /*event_max*/, string &/*author*/, map<string, string> &/*svals*/, string /*comment*/)
0083 {
0084     LOG<<"PutCalib(string namepath, int run_min, int run_max, int event_min, int event_max, string &author, map<string, string> &svals, string &comment="") not implemented!"<<LOG_END;
0085     return true;
0086 }
0087 
0088 //---------------------------------
0089 // PutCalib
0090 //---------------------------------
0091 bool JCalibration::PutCalib(string /*namepath*/, int32_t /*run_min*/, int32_t /*run_max*/, uint64_t /*event_min*/, uint64_t /*event_max*/, string &/*author*/, vector< map<string, string> > &/*svals*/, string /*comment*/)
0092 {
0093     LOG<<"PutCalib(string namepath, int run_min, int run_max, int event_min, int event_max, string &author, vector< map<string, string> > &svals, string &comment="") not implemented!"<<LOG_END;
0094     return true;
0095 }
0096 
0097 //---------------------------------
0098 // RecordRequest
0099 //---------------------------------
0100 void JCalibration::RecordRequest(string namepath, string type_name)
0101 {
0102     /// Record a request for a set of calibration constants.
0103 
0104     // Lock mutex when accessing "accesses" container.
0105     pthread_mutex_lock(&accesses_mutex);
0106 
0107     map<string, vector<string> >::iterator iter = accesses.find(namepath);
0108     if(iter==accesses.end()){
0109         vector<string> types;
0110         types.push_back(type_name);
0111         accesses[namepath] = types;
0112     }else{
0113         iter->second.push_back(type_name);
0114     }
0115 
0116     pthread_mutex_unlock(&accesses_mutex);
0117 }
0118 
0119 //---------------------------------
0120 // GetEventBoundaries
0121 //---------------------------------
0122 void JCalibration::GetEventBoundaries(vector<uint64_t> &event_boundaries)
0123 {
0124     /// Copy the event boundaries (if any) for this calibration's run
0125     /// into the caller supplied container. The contents of the
0126     /// container are replaced. If there are no boundaries, then the
0127     /// container is cleared and returned empty.
0128 
0129     // lock mutex
0130     pthread_mutex_lock(&boundaries_mutex);
0131 
0132     // If we haven't retrieved the boundaries yet, then do so now
0133     if(!retrieved_event_boundaries){
0134         RetrieveEventBoundaries();
0135         retrieved_event_boundaries = true;
0136     }
0137 
0138     // unlock mutex
0139     pthread_mutex_unlock(&boundaries_mutex);
0140 
0141     // Copy boundaries to the caller's container
0142     event_boundaries = this->event_boundaries;
0143 }
0144 
0145 //---------------------------------
0146 // GetVariation
0147 //---------------------------------
0148 string JCalibration::GetVariation(void)
0149 {
0150     /// This is a special routine that looks for a string
0151     /// of the format "variation=XXX" in the context string
0152     /// and if found, returns the "XXX" part. Otherwise, it
0153     /// returns "default" assuming no variation was identified.
0154     /// This is here for convenience since the CCDB implementation
0155     /// will use strings of this format to specify variations.
0156     /// When looking for the variation, any spaces or semi-colon
0157     /// found in the string will be removed along with characters
0158     /// following it. This is to allow semi-colon or space seperated
0159     /// lists in the variation.
0160     if(context == "default") return context;
0161 
0162     size_t pos = context.find("variation=");
0163     if(pos != context.npos){
0164         string variation = context.substr(pos+string("variation=").length());
0165 
0166         // chop of ";" and everything after it
0167         pos = variation.find(";");
0168         if(pos != context.npos){
0169             variation = variation.substr(0, pos);
0170         }
0171 
0172         // chop off space and everything after it
0173         pos = variation.find(" ");
0174         if(pos != context.npos){
0175             variation = variation.substr(0, pos);
0176         }
0177 
0178         return variation;
0179     }
0180 
0181     return "default";
0182 }
0183 
0184 //---------------------------------
0185 // GetContainerType
0186 //---------------------------------
0187 JCalibration::containerType_t JCalibration::GetContainerType(string typeid_name)
0188 {
0189     containerType_t ctype = kUnknownType;
0190 
0191     if(ctype==kUnknownType)ctype=TrycontainerType<         double>(typeid_name);
0192     if(ctype==kUnknownType)ctype=TrycontainerType<         float>(typeid_name);
0193     if(ctype==kUnknownType)ctype=TrycontainerType<         int>(typeid_name);
0194     if(ctype==kUnknownType)ctype=TrycontainerType<         long>(typeid_name);
0195     if(ctype==kUnknownType)ctype=TrycontainerType<         short>(typeid_name);
0196     if(ctype==kUnknownType)ctype=TrycontainerType<         char>(typeid_name);
0197     if(ctype==kUnknownType)ctype=TrycontainerType<unsigned int>(typeid_name);
0198     if(ctype==kUnknownType)ctype=TrycontainerType<unsigned long>(typeid_name);
0199     if(ctype==kUnknownType)ctype=TrycontainerType<unsigned short>(typeid_name);
0200     if(ctype==kUnknownType)ctype=TrycontainerType<unsigned char>(typeid_name);
0201     if(ctype==kUnknownType)ctype=TrycontainerType<         string>(typeid_name);
0202 
0203     return ctype;
0204 }
0205 
0206 //---------------------------------
0207 // DumpCalibrationsToFiles
0208 //---------------------------------
0209 void JCalibration::DumpCalibrationsToFiles(string basedir)
0210 {
0211     /// This method will loop through all of the namespaces in the access list
0212     /// and dump them into a set of files that can be read using the JCalibrationFile
0213     /// sub-class. This can be used, for example, to capture the specific slice
0214     /// of the calibration database used for the current job for use by subsequent
0215     /// similar jobs.
0216 
0217     // Create base directory for writing calibrations into
0218     mode_t mode=S_IRWXU | S_IRWXG | S_IRWXO;
0219     char str[256];
0220     snprintf(str, 256, "calib%d/", GetRun());
0221     basedir += string(str);
0222     mkdir(basedir.c_str(), mode);
0223 
0224     // Make one pass through the namepaths just to get the maximum length
0225     unsigned int max_namepath_len=0;
0226     map<string, vector<string> >::iterator iter;
0227     for(iter=accesses.begin(); iter!=accesses.end(); iter++){
0228         if(iter->first.length()>max_namepath_len)max_namepath_len=iter->first.length();
0229     }
0230 
0231     // Print header
0232     cout<<endl;
0233     cout<<"Dumping calibrations for this job in \""<<basedir<<"\""<<endl;
0234     cout<<"Calibrations obtained from:"<<endl;
0235     cout<<"             URL: "<<GetURL()<<endl;
0236     cout<<"         Context: "<<GetContext()<<endl;
0237     cout<<"      Run Number: "<<GetRun()<<endl;
0238     cout<<endl;
0239     string header = string("namepath") + string(max_namepath_len-8+2,' ') + "data type";
0240     cout<<header<<endl;
0241     cout<<string(max_namepath_len,'_')<<"  "<<string(20,'_') <<endl;
0242 
0243     // Loop over namepaths in access list
0244     for(iter=accesses.begin(); iter!=accesses.end(); iter++){
0245 
0246         // Get namepath
0247         string namepath = iter->first;
0248 
0249         // Check that all accesses used the same data type so we can warn user if
0250         // different container types were used.
0251         vector<string> &typeid_names = iter->second;
0252         if(typeid_names.size()<1){
0253             LOG<<"typeid_names.size()<1 : This should never happen!!"<<LOG_END;
0254             continue;
0255         }
0256         string typeid_name = typeid_names[0];
0257         for(unsigned int i=1; i<typeid_names.size(); i++){
0258             if(typeid_names[i]!=typeid_name){
0259                 LOG<<"Type mismatch for namepath "<<namepath<<LOG_END;
0260                 LOG<<"type1: "<<typeid_name<<"  type2:"<<typeid_names[i]<<LOG_END;
0261                 LOG<<"type1 will be used";
0262             }
0263         }
0264 
0265         // Parse namepath into elements separated by "/"s
0266         string str = namepath;
0267         vector<string> path_elements;
0268         unsigned int cutAt;
0269         while( (cutAt = str.find("/")) != (unsigned int)str.npos ){
0270             if(cutAt > 0)path_elements.push_back(str.substr(0,cutAt));
0271             str = str.substr(cutAt+1);
0272         }
0273         if(str.length() > 0)path_elements.push_back(str);
0274 
0275         // If we have no path_elements, then we've nothing to do
0276         if(path_elements.size()<1){
0277             LOG<<"Unable to parse namepath "<<namepath<<LOG_END;
0278             continue;
0279         }
0280 
0281         // Create directories to hold these constants. The directories may
0282         // already exist, but that's OK.
0283         string dir = basedir;
0284         for(unsigned int i=0; i<path_elements.size()-1; i++){
0285             dir += path_elements[i]+"/";
0286             mkdir(dir.c_str(), mode);
0287         }
0288 
0289         // Print namepath and data type
0290         cout<<namepath<<string(max_namepath_len-namepath.length()+2,' ')<<typeid_name<<endl;
0291 
0292         // Get container type and write file for this set of constants
0293         switch(GetContainerType(typeid_name)){
0294             case kVector:
0295                 WriteCalibFileVector(dir, path_elements[path_elements.size()-1], namepath);
0296                 break;
0297             case kMap:
0298                 WriteCalibFileMap(dir, path_elements[path_elements.size()-1], namepath);
0299                 break;
0300             case kVectorVector:
0301                 WriteCalibFileVectorVector(dir, path_elements[path_elements.size()-1], namepath);
0302                 break;
0303             case kVectorMap:
0304                 WriteCalibFileVectorMap(dir, path_elements[path_elements.size()-1], namepath);
0305                 break;
0306             default:
0307                 LOG<<"Unknown container type for namepath \""<<namepath<<"\" skipping..."<<LOG_END;
0308         }
0309     }
0310 
0311     // Write out the info.xml file to record where these values came from
0312     string fname_info = basedir+"info.xml";
0313     ofstream ofs(fname_info.c_str());
0314     if(ofs.is_open()){
0315         time_t now = time(NULL);
0316         string datetime(ctime(&now));
0317         ofs<<"<jcalibration>"<<endl;
0318         ofs<<"  <URL>"<<GetURL()<<"</URL>"<<endl;
0319         ofs<<"  <Context>"<<GetContext()<<"</Context>"<<endl;
0320         ofs<<"  <RunNumber>"<<GetRun()<<"</RunNumber>"<<endl;
0321         ofs<<"  <datetime>"<<datetime.substr(0,datetime.length()-1)<<"</datetime>"<<endl;
0322         ofs<<"  <timestamp>"<<now<<"</timestamp>"<<endl;
0323         ofs<<"</jcalibration>"<<endl;
0324     }
0325 
0326     // Determine an appropriate URL for these files
0327 
0328     // What we want is the full path to the top-level directory of
0329     // the calibration files regardless whether basedir is
0330     // a full or relative path.
0331     char fullpath[1024]="";
0332     DIR *dirp = opendir("./"); // this trick suggested by getcwd man page for saving/restoring cwd
0333     int err = chdir(basedir.c_str());         // cd into the basedir directory
0334     if(!err)  err = (getcwd(fullpath, 1024)==NULL); // get full path of basedir directory
0335     if(dirp){
0336         fchdir(dirfd(dirp));                        // cd back into the working directory we started in
0337         closedir(dirp);
0338     }
0339     if(err != 0){
0340         jerr<<" Error getting full pathname to directory where the calib constants were written!" << endl;
0341         jerr<<" It's possible you can still access them using the info below, but this is" << endl;
0342         jerr<<" likely a critical error!" << endl;
0343         if(basedir.length() >1023) basedir = "/fatal/error/its/hopeless/"; // ;)
0344         strcpy(fullpath, basedir.c_str());
0345     }
0346 
0347     string newurl = string("file://")+fullpath;
0348 
0349     // Print footer
0350     cout<<endl;
0351     cout<<"To access these constants with another JANA program set your"<<endl;
0352     cout<<"JANA_CALIB_URL environment variable as follows:"<<endl;
0353     cout<<endl;
0354     cout<<"for tcsh:"<<endl;
0355     cout<<"       setenv JANA_CALIB_URL \""<<newurl<<"\""<<endl;
0356     cout<<endl;
0357     cout<<"for bash:"<<endl;
0358     cout<<"       export JANA_CALIB_URL=\""<<newurl<<"\""<<endl;
0359     cout<<endl;
0360 }
0361 
0362 //---------------------------------
0363 // WriteCalibFileVector
0364 //---------------------------------
0365 void JCalibration::WriteCalibFileVector(string dir, string fname, string namepath)
0366 {
0367     // Open output file
0368     string fullpath = dir+fname;
0369     ofstream ofs(fullpath.c_str());
0370     if(!ofs.is_open()){LOG<<"Unable to open file: "<<fullpath<<" !"<<LOG_END; return;}
0371 
0372     // Get constants and check for error
0373     map<string,string> vals;
0374     if(GetCalib(namepath, vals)){
0375         LOG<<"Error getting values for: "<<namepath<<" !"<<LOG_END;
0376     }else{
0377         // Write constants to file
0378         map<string,string>::iterator iter;
0379         for(iter=vals.begin(); iter!=vals.end(); iter++){
0380             ofs<<iter->second<<std::endl;
0381         }
0382     }
0383 
0384     ofs.close();
0385 }
0386 
0387 //---------------------------------
0388 // WriteCalibFileMap
0389 //---------------------------------
0390 void JCalibration::WriteCalibFileMap(string dir, string fname, string namepath)
0391 {
0392     // Open output file
0393     string fullpath = dir+fname;
0394     ofstream ofs(fullpath.c_str());
0395     if(!ofs.is_open()){LOG<<"Unable to open file: "<<fullpath<<" !"<<LOG_END; return;}
0396 
0397     // Get constants and check for error
0398     map<string,string> vals;
0399     if(GetCalib(namepath, vals)){
0400         LOG<<"Error getting values for: "<<namepath<<" !"<<LOG_END;
0401     }else{
0402         // Write constants to file
0403         map<string,string>::iterator iter;
0404         for(iter=vals.begin(); iter!=vals.end(); iter++){
0405             ofs<<iter->first<<"\t"<<iter->second<<endl;
0406         }
0407     }
0408 
0409     ofs.close();
0410 }
0411 
0412 //---------------------------------
0413 // WriteCalibFileVectorVector
0414 //---------------------------------
0415 void JCalibration::WriteCalibFileVectorVector(string dir, string fname, string namepath)
0416 {
0417     // Open output file
0418     string fullpath = dir+fname;
0419     ofstream ofs(fullpath.c_str());
0420     if(!ofs.is_open()){LOG<<"Unable to open file: "<<fullpath<<" !"<<LOG_END; return;}
0421 
0422     // Get constants and check for error
0423     vector<map<string,string> > vals;
0424     if(GetCalib(namepath, vals)){
0425         LOG<<"Error getting values for: "<<namepath<<" !"<<LOG_END;
0426     }else{
0427         // Write constants to file
0428 
0429         // Loop over rows
0430         vector<map<string,string> >::iterator viter;
0431         for(viter=vals.begin(); viter!=vals.end(); viter++){
0432 
0433             // Loop over columns writing values
0434             map<string,string>::iterator iter;
0435             for(iter=viter->begin(); iter!=viter->end(); iter++){
0436                 ofs<<" "<<iter->second;
0437             }
0438             ofs<<endl;
0439         }
0440     }
0441 
0442     ofs.close();
0443 }
0444 
0445 //---------------------------------
0446 // WriteCalibFileVectorMap
0447 //---------------------------------
0448 void JCalibration::WriteCalibFileVectorMap(string dir, string fname, string namepath)
0449 {
0450     // Open output file
0451     string fullpath = dir+fname;
0452     ofstream ofs(fullpath.c_str());
0453     if(!ofs.is_open()){LOG<<"Unable to open file: "<<fullpath<<" !"<<LOG_END; return;}
0454 
0455     // Get constants and check for error
0456     vector<map<string,string> > vals;
0457     if(GetCalib(namepath, vals)){
0458         LOG<<"Error getting values for: "<<namepath<<" !"<<LOG_END;
0459     }else{
0460         // Write constants to file
0461 
0462         // Loop over rows
0463         vector<map<string,string> >::iterator viter;
0464         for(viter=vals.begin(); viter!=vals.end(); viter++){
0465 
0466             // If this is the first row, write the header line
0467             map<string,string>::iterator iter;
0468             if(viter==vals.begin()){
0469                 ofs<<"#%";
0470                 for(iter=viter->begin(); iter!=viter->end(); iter++){
0471                     ofs<<"  "<<iter->first;
0472                 }
0473                 ofs<<endl;
0474             }
0475 
0476             // Loop over columns writing values
0477             for(iter=viter->begin(); iter!=viter->end(); iter++){
0478                 ofs<<" "<<iter->second;
0479             }
0480             ofs<<endl;
0481         }
0482     }
0483 
0484     ofs.close();
0485 }
0486