Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-07-06 08:57:17

0001 
0002 // Copyright 2007-2025, Jefferson Science Associates, LLC.
0003 // Subject to the terms in the LICENSE file found in the top-level directory.
0004 // Author: David Lawrence
0005 
0006 #pragma once
0007 #include <JANA/Calibrations/JCalibration.h>
0008 #include <JANA/Calibrations/JCalibrationFile.h>
0009 #include <JANA/Calibrations/JCalibrationGenerator.h>
0010 
0011 #include <JANA/JService.h>
0012 
0013 #include <algorithm>
0014 #include "JANA/Services/JParameterManager.h"
0015 #include "JResource.h"
0016 
0017 class JCalibrationManager : public JService {
0018 
0019     vector<JCalibration *> m_calibrations;
0020     vector<JResource *> m_resource_managers;
0021     vector<JCalibrationGenerator *> m_calibration_generators;
0022 
0023     pthread_mutex_t m_calibration_mutex;
0024     pthread_mutex_t m_resource_manager_mutex;
0025 
0026     std::shared_ptr<JParameterManager> m_params;
0027 
0028     std::string m_url = "file://./";
0029     std::string m_context = "default";
0030 
0031 public:
0032 
0033     JCalibrationManager() { 
0034         pthread_mutex_init(&m_calibration_mutex, nullptr);
0035         pthread_mutex_init(&m_resource_manager_mutex, nullptr);
0036 
0037         SetPrefix("jana"); 
0038     }
0039 
0040     void acquire_services(JServiceLocator* sl) {
0041 
0042         // Url and context may be passed in either as environment variables
0043         // or configuration parameters. Default values are used if neither is available.
0044 
0045         if (getenv("JANA_CALIB_URL") != nullptr) m_url = getenv("JANA_CALIB_URL");
0046         if (getenv("JANA_CALIB_CONTEXT") != nullptr) m_context = getenv("JANA_CALIB_CONTEXT");
0047 
0048         m_params = sl->get<JParameterManager>();
0049         m_params->SetDefaultParameter("JANA:CALIB_URL", m_url, "URL used to access calibration constants");
0050         m_params->SetDefaultParameter("JANA:CALIB_CONTEXT", m_context,
0051                                     "Calibration context to pass on to concrete JCalibration derived class");
0052         m_params->RegisterParameter("ccdb:cache", true, "Enable CCDB Caching");
0053 
0054         for(auto generator:m_calibration_generators) {
0055             generator->SetApplication(GetApplication());
0056         }
0057     }
0058 
0059     void AddCalibrationGenerator(JCalibrationGenerator *generator) {
0060         m_calibration_generators.push_back(generator);
0061     };
0062 
0063     void RemoveCalibrationGenerator(JCalibrationGenerator *generator) {
0064 
0065         vector<JCalibrationGenerator *> &f = m_calibration_generators;
0066         vector<JCalibrationGenerator *>::iterator iter = std::find(f.begin(), f.end(), generator);
0067         if (iter != f.end())f.erase(iter);
0068     }
0069 
0070     vector<JCalibrationGenerator *> GetCalibrationGenerators() { return m_calibration_generators; }
0071 
0072     void GetJCalibrations(vector<JCalibration *> &calibs) { calibs = m_calibrations; }
0073 
0074     JCalibration *GetJCalibration(unsigned int run_number) {
0075         /// Return a pointer to the JCalibration object that is valid for the given run number.
0076         ///
0077         /// This first searches through the list of existing JCalibration objects (created by JCalibrationManager)
0078         /// to see if it already has the right one. If so, a pointer to it is returned. If not, a new JCalibration
0079         /// object is created and added to the internal list. Note that since we need to make sure the list is not
0080         /// modified by one thread while being searched by another, a mutex is locked while searching the list.
0081         /// It is <b>NOT</b> efficient to get or even use the JCalibration object every event. Factories should access
0082         /// it in their brun() callback and keep a local copy of the required constants for use in the evnt() callback.
0083 
0084 
0085         // Lock mutex to keep list from being modified while we search it
0086         pthread_mutex_lock(&m_calibration_mutex);
0087 
0088         vector<JCalibration *>::iterator iter = m_calibrations.begin();
0089         for (; iter != m_calibrations.end(); iter++) {
0090             if ((*iter)->GetRun() != (int) run_number)continue;
0091             if ((*iter)->GetURL() != m_url)continue;                    // These allow specialty programs to change
0092             if ((*iter)->GetContext() != m_context)continue;        // the source and still use us to instantiate
0093             // Found it! Unlock mutex and return pointer
0094             JCalibration *g = *iter;
0095             pthread_mutex_unlock(&m_calibration_mutex);
0096             return g;
0097         }
0098 
0099         // JCalibration object for this run_number doesn't exist in our list. Create a new one and add it to the list.
0100         // We need to create an object of the appropriate subclass of JCalibration. This determined by looking through the
0101         // existing JCalibrationGenerator objects and finding the which claims the highest probability of being able to
0102         // open it based on the URL. If there are no generators claiming a non-zero probability and the URL starts with
0103         // "file://", then a JCalibrationFile object is created (i.e. we don't bother making a JCalibrationGeneratorFile
0104         // class and instead, handle it here.)
0105 
0106         JCalibrationGenerator *gen = nullptr;
0107         double liklihood = 0.0;
0108         for (unsigned int i = 0; i < m_calibration_generators.size(); i++) {
0109             double my_liklihood = m_calibration_generators[i]->CheckOpenable(m_url, run_number, m_context);
0110             if (my_liklihood > liklihood) {
0111                 liklihood = my_liklihood;
0112                 gen = m_calibration_generators[i];
0113             }
0114         }
0115 
0116         // Make the JCalibration object
0117         JCalibration *g = nullptr;
0118         if (gen) {
0119             g = gen->MakeJCalibration(m_url, run_number, m_context);
0120         }
0121         if (gen == nullptr && (m_url.find("file://") == 0)) {
0122             g = new JCalibrationFile(m_url, run_number, m_context);
0123         }
0124         if (g) {
0125             m_calibrations.push_back(g);
0126             LOG_INFO(m_logger)
0127                 << "Created JCalibration object of type: " << g->className() << "\n"
0128                 << "  Generated via: "
0129                 << (gen == nullptr ? "fallback creation of JCalibrationFile" : gen->Description())
0130                 << "\n"
0131                 << "  Run: " << g->GetRun() << "\n"
0132                 << "  URL: " << g->GetURL() << "\n"
0133                 << "  context: " << g->GetContext()
0134                 << LOG_END;
0135         } else {
0136             JLogMessage m(m_logger, JLogger::Level::ERROR);
0137             m << "Unable to create JCalibration object!\n"
0138               << "  Run: " << run_number << "\n"
0139               << "  URL: " << m_url << "\n"
0140               << "  context: " << m_context << "\n";
0141 
0142             if (gen) {
0143                 m << "  Attempted to use generator: " << gen->Description();
0144             } else {
0145                 m << "  No appropriate generators found. Attempted JCalibrationFile";
0146             }
0147             std::move(m) << LOG_END;
0148         }
0149 
0150         // Unlock calibration mutex
0151         pthread_mutex_unlock(&m_calibration_mutex);
0152         return g;
0153     }
0154 
0155     template<class T>
0156     bool GetCalib(unsigned int run_number, unsigned int event_number, string namepath, map<string, T> &vals) {
0157         /// Get the JCalibration object from JApplication for the run number of
0158         /// the current event and call its Get() method to get the constants.
0159 
0160         // Note that we could do this by making "vals" a generic type T thus, combining
0161         // this with the vector version below. However, doing this explicitly will make
0162         // it easier for the user to understand how to call us.
0163 
0164         vals.clear();
0165         JCalibration *calib = GetJCalibration(run_number);
0166         if (!calib) {
0167             LOG_ERROR(m_logger) << "Unable to get JCalibration object for run " << run_number << LOG_END;
0168             return true;
0169         }
0170         return calib->Get(namepath, vals, event_number);
0171     }
0172 
0173     template<class T>
0174     bool GetCalib(unsigned int run_number, unsigned int event_number, string namepath, vector<T> &vals) {
0175         /// Get the JCalibration object from JApplication for the run number of
0176         /// the current event and call its Get() method to get the constants.
0177 
0178         vals.clear();
0179         JCalibration *calib = GetJCalibration(run_number);
0180         if (!calib) {
0181             LOG_ERROR(m_logger) << "Unable to get JCalibration object for run " << run_number << LOG_END;
0182             return true;
0183         }
0184         return calib->Get(namepath, vals, event_number);
0185     }
0186 
0187     JResource* GetResource(unsigned int run_number = 0) {
0188 
0189         /// Return a pointer to the JResource object for the specified run_number. If no run_number is given or a
0190         /// value of 0 is given, then the first element from the list of resource managers is returned. If no managers
0191         /// currently exist, one will be created using one of the following in order of precedence:
0192         /// 1. JCalibration corresponding to given run number
0193         /// 2. First JCalibration object in list (used when run_number is zero)
0194         /// 3. No backing JCalibration object.
0195         ///
0196         /// The JCalibration is used to hold the URLs of resources so when a namepath is specified, the location of the
0197         /// resource on the web can be obtained and the file downloaded if necessary. See documentation in the JResourceManager
0198         /// class for more details.
0199 
0200         // Handle case for when no run number is specified
0201         if (run_number == 0) {
0202             pthread_mutex_lock(&m_resource_manager_mutex);
0203             if (m_resource_managers.empty()) {
0204                 if (m_calibrations.empty()) {
0205                     m_resource_managers.push_back(new JResource(m_params, nullptr));
0206                 } else {
0207                     m_resource_managers.push_back(new JResource(m_params, m_calibrations[0]));
0208                 }
0209             }
0210             pthread_mutex_unlock(&m_resource_manager_mutex);
0211 
0212             return m_resource_managers[0];
0213         }
0214 
0215         // Run number is non-zero. Use it to get a JCalibration pointer
0216         JCalibration *jcalib = GetJCalibration(run_number);
0217         for (unsigned int i = 0; i < m_resource_managers.size(); i++) {
0218             if (m_resource_managers[i]->GetJCalibration() == jcalib)return m_resource_managers[i];
0219         }
0220 
0221         // No resource manager exists for the JCalibration that corresponds to the given run_number. Create one.
0222         JResource *resource_manager = new JResource(m_params, jcalib);
0223         pthread_mutex_lock(&m_resource_manager_mutex);
0224         m_resource_managers.push_back(resource_manager);
0225         pthread_mutex_unlock(&m_resource_manager_mutex);
0226 
0227         return resource_manager;
0228 
0229     }
0230 
0231 };
0232 
0233