Back to home page

EIC code displayed by LXR

 
 

    


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

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     }
0053 
0054     void AddCalibrationGenerator(JCalibrationGenerator *generator) {
0055         m_calibration_generators.push_back(generator);
0056     };
0057 
0058     void RemoveCalibrationGenerator(JCalibrationGenerator *generator) {
0059 
0060         vector<JCalibrationGenerator *> &f = m_calibration_generators;
0061         vector<JCalibrationGenerator *>::iterator iter = std::find(f.begin(), f.end(), generator);
0062         if (iter != f.end())f.erase(iter);
0063     }
0064 
0065     vector<JCalibrationGenerator *> GetCalibrationGenerators() { return m_calibration_generators; }
0066 
0067     void GetJCalibrations(vector<JCalibration *> &calibs) { calibs = m_calibrations; }
0068 
0069     JCalibration *GetJCalibration(unsigned int run_number) {
0070         /// Return a pointer to the JCalibration object that is valid for the given run number.
0071         ///
0072         /// This first searches through the list of existing JCalibration objects (created by JCalibrationManager)
0073         /// to see if it already has the right one. If so, a pointer to it is returned. If not, a new JCalibration
0074         /// object is created and added to the internal list. Note that since we need to make sure the list is not
0075         /// modified by one thread while being searched by another, a mutex is locked while searching the list.
0076         /// It is <b>NOT</b> efficient to get or even use the JCalibration object every event. Factories should access
0077         /// it in their brun() callback and keep a local copy of the required constants for use in the evnt() callback.
0078 
0079 
0080         // Lock mutex to keep list from being modified while we search it
0081         pthread_mutex_lock(&m_calibration_mutex);
0082 
0083         vector<JCalibration *>::iterator iter = m_calibrations.begin();
0084         for (; iter != m_calibrations.end(); iter++) {
0085             if ((*iter)->GetRun() != (int) run_number)continue;
0086             if ((*iter)->GetURL() != m_url)continue;                    // These allow specialty programs to change
0087             if ((*iter)->GetContext() != m_context)continue;        // the source and still use us to instantiate
0088             // Found it! Unlock mutex and return pointer
0089             JCalibration *g = *iter;
0090             pthread_mutex_unlock(&m_calibration_mutex);
0091             return g;
0092         }
0093 
0094         // JCalibration object for this run_number doesn't exist in our list. Create a new one and add it to the list.
0095         // We need to create an object of the appropriate subclass of JCalibration. This determined by looking through the
0096         // existing JCalibrationGenerator objects and finding the which claims the highest probability of being able to
0097         // open it based on the URL. If there are no generators claiming a non-zero probability and the URL starts with
0098         // "file://", then a JCalibrationFile object is created (i.e. we don't bother making a JCalibrationGeneratorFile
0099         // class and instead, handle it here.)
0100 
0101         JCalibrationGenerator *gen = nullptr;
0102         double liklihood = 0.0;
0103         for (unsigned int i = 0; i < m_calibration_generators.size(); i++) {
0104             double my_liklihood = m_calibration_generators[i]->CheckOpenable(m_url, run_number, m_context);
0105             if (my_liklihood > liklihood) {
0106                 liklihood = my_liklihood;
0107                 gen = m_calibration_generators[i];
0108             }
0109         }
0110 
0111         // Make the JCalibration object
0112         JCalibration *g = nullptr;
0113         if (gen) {
0114             g = gen->MakeJCalibration(m_url, run_number, m_context);
0115         }
0116         if (gen == nullptr && (m_url.find("file://") == 0)) {
0117             g = new JCalibrationFile(m_url, run_number, m_context);
0118         }
0119         if (g) {
0120             m_calibrations.push_back(g);
0121             LOG_INFO(m_logger)
0122                 << "Created JCalibration object of type: " << g->className() << "\n"
0123                 << "  Generated via: "
0124                 << (gen == nullptr ? "fallback creation of JCalibrationFile" : gen->Description())
0125                 << "\n"
0126                 << "  Run: " << g->GetRun() << "\n"
0127                 << "  URL: " << g->GetURL() << "\n"
0128                 << "  context: " << g->GetContext()
0129                 << LOG_END;
0130         } else {
0131             JLogMessage m(m_logger, JLogger::Level::ERROR);
0132             m << "Unable to create JCalibration object!\n"
0133               << "  Run: " << run_number << "\n"
0134               << "  URL: " << m_url << "\n"
0135               << "  context: " << m_context << "\n";
0136 
0137             if (gen) {
0138                 m << "  Attempted to use generator: " << gen->Description();
0139             } else {
0140                 m << "  No appropriate generators found. Attempted JCalibrationFile";
0141             }
0142             std::move(m) << LOG_END;
0143         }
0144 
0145         // Unlock calibration mutex
0146         pthread_mutex_unlock(&m_calibration_mutex);
0147         return g;
0148     }
0149 
0150     template<class T>
0151     bool GetCalib(unsigned int run_number, unsigned int event_number, string namepath, map<string, T> &vals) {
0152         /// Get the JCalibration object from JApplication for the run number of
0153         /// the current event and call its Get() method to get the constants.
0154 
0155         // Note that we could do this by making "vals" a generic type T thus, combining
0156         // this with the vector version below. However, doing this explicitly will make
0157         // it easier for the user to understand how to call us.
0158 
0159         vals.clear();
0160         JCalibration *calib = GetJCalibration(run_number);
0161         if (!calib) {
0162             LOG_ERROR(m_logger) << "Unable to get JCalibration object for run " << run_number << LOG_END;
0163             return true;
0164         }
0165         return calib->Get(namepath, vals, event_number);
0166     }
0167 
0168     template<class T>
0169     bool GetCalib(unsigned int run_number, unsigned int event_number, string namepath, vector<T> &vals) {
0170         /// Get the JCalibration object from JApplication for the run number of
0171         /// the current event and call its Get() method to get the constants.
0172 
0173         vals.clear();
0174         JCalibration *calib = GetJCalibration(run_number);
0175         if (!calib) {
0176             LOG_ERROR(m_logger) << "Unable to get JCalibration object for run " << run_number << LOG_END;
0177             return true;
0178         }
0179         return calib->Get(namepath, vals, event_number);
0180     }
0181 
0182     JResource* GetResource(unsigned int run_number = 0) {
0183 
0184         /// Return a pointer to the JResource object for the specified run_number. If no run_number is given or a
0185         /// value of 0 is given, then the first element from the list of resource managers is returned. If no managers
0186         /// currently exist, one will be created using one of the following in order of precedence:
0187         /// 1. JCalibration corresponding to given run number
0188         /// 2. First JCalibration object in list (used when run_number is zero)
0189         /// 3. No backing JCalibration object.
0190         ///
0191         /// The JCalibration is used to hold the URLs of resources so when a namepath is specified, the location of the
0192         /// resource on the web can be obtained and the file downloaded if necessary. See documentation in the JResourceManager
0193         /// class for more details.
0194 
0195         // Handle case for when no run number is specified
0196         if (run_number == 0) {
0197             pthread_mutex_lock(&m_resource_manager_mutex);
0198             if (m_resource_managers.empty()) {
0199                 if (m_calibrations.empty()) {
0200                     m_resource_managers.push_back(new JResource(m_params, nullptr));
0201                 } else {
0202                     m_resource_managers.push_back(new JResource(m_params, m_calibrations[0]));
0203                 }
0204             }
0205             pthread_mutex_unlock(&m_resource_manager_mutex);
0206 
0207             return m_resource_managers[0];
0208         }
0209 
0210         // Run number is non-zero. Use it to get a JCalibration pointer
0211         JCalibration *jcalib = GetJCalibration(run_number);
0212         for (unsigned int i = 0; i < m_resource_managers.size(); i++) {
0213             if (m_resource_managers[i]->GetJCalibration() == jcalib)return m_resource_managers[i];
0214         }
0215 
0216         // No resource manager exists for the JCalibration that corresponds to the given run_number. Create one.
0217         JResource *resource_manager = new JResource(m_params, jcalib);
0218         pthread_mutex_lock(&m_resource_manager_mutex);
0219         m_resource_managers.push_back(resource_manager);
0220         pthread_mutex_unlock(&m_resource_manager_mutex);
0221 
0222         return resource_manager;
0223 
0224     }
0225 
0226     [[deprecated("Replaced with GetResource()")]]
0227     JResource *GetLargeCalibration(unsigned int run_number = 0) {
0228         return GetResource(run_number);
0229     }
0230 
0231 };
0232 
0233