Warning, /jana2/docs/jana1to2/developers-transition-guide.md is written in an unsupported language. File is not indexed.
0001
0002
0003 # Developers Transition Guide
0004
0005 ***Key Syntax Changes between JANA1 to JANA2***
0006
0007 This guide outlines the critical syntax and functional updates between JANA1 and JANA2, helping developers navigate the transition smoothly.
0008
0009
0010
0011 ## Namespace
0012 ##### **JANA1**
0013 Adding following on top of all files was necessary in JANA1:
0014
0015 ```
0016 using namespace jana;
0017 ```
0018 ##### **JANA2**
0019 This line is no longer required in JANA2.
0020
0021
0022 ## Application
0023
0024 ### JApplication
0025 #### Getting the JApplication
0026
0027 ##### **JANA1**
0028 In JANA1 there is a global variable `japp` which is a pointer to the project's `JApplication`. You can also obtain it from `JEventLoop::GetJApplication()`.
0029
0030 ##### **JANA2**
0031 In JANA2, `japp` is still around but we are strongly discouraging its future use. If you are within any JANA component (for instance: JFactory, JEventProcessor, JEventSource, JService) you can obtain the `JApplication` pointer from `this`, like so:
0032
0033 ```cpp
0034 auto app = GetApplication();
0035 ```
0036
0037 You can also obtain it from the `JEvent` the same way as you used to from `JEventLoop`, i.e.
0038
0039 ```cpp
0040 auto app = event->GetJApplication();
0041 ```
0042
0043 ### DApplication
0044 ### Getting DApplication
0045 ##### **JANA1**
0046
0047 ```cpp
0048 #include "DANA/DApplication.h"
0049 dApplication = dynamic_cast<DApplication*>(locEventLoop->GetJApplication
0050 ```
0051
0052 ##### **JANA2**
0053 There is no `DApplication` anymore in JANA2. `JApplication` is `final`, which means you can't inherit from it. The functionality on `DApplication` has been moved into `JService`s, which can be accessed via `JApplication::GetService<ServiceT>()`.
0054
0055 ```cpp
0056 auto dapp = GetApplication()->GetService<DApplication>();
0057 ```
0058
0059
0060 ## Parameter Manager
0061 ### Setting Parameters
0062
0063 ##### **JANA1**
0064
0065 ```cpp
0066 gPARMS->SetDefaultParameter("component_prefix:value_name", ref_to_member_var);
0067 ```
0068
0069 ##### **JANA2**
0070 You should set parameters as shown below.
0071
0072 ```cpp
0073 auto app = GetApplication();
0074 app->SetDefaultParameter("component_prefix:value_name", ref_to_member_var);
0075 ```
0076
0077 We strongly recommend you register all parameters from inside the `Init()` callbacks of your JANA components, or from `InitPlugin()`. This helps JANA:
0078
0079 - Report back which parameters are available without having to process an input file.
0080 - Emit a warning (or error!) when a user-provided parameter is misspelled
0081 - Emit a warning when two plugins register the same parameter with conflicting default values.
0082 - Inspect the exact parameter values used by a factory
0083
0084 If you register parameters in other contexts, this machinery might not work and you might get incomplete parameter lists and missing or spurious error messages. Worse, your code might not see the parameter values you expect it to see. Registering parameters from inside constructors is less problematic but still discouraged because it won't work with some upcoming new features.
0085
0086 ### Getting Parameters
0087
0088 ##### **JANA1**
0089
0090 ```cpp
0091 gPARMS->GetParameter("component_prefix:value_name", ref_to_member_var);
0092 ```
0093
0094 ##### **JANA2**
0095 ```cpp
0096 auto app = GetApplication();
0097 // Method 1
0098 app->GetParameter("component_prefix:value_name", member_var);
0099 // Method 2
0100 member_var = app->GetParameterValue<value_type>("component_prefix:value_name");
0101 ```
0102
0103
0104 ### Getting Parameter Maps
0105
0106 ##### **JANA1**
0107 To obtain a map of all parameters that share a common prefix:
0108
0109 ```cpp
0110 //gets all parameters with this filter at the beginning of the key
0111 gPARMS->GetParameters(locParameterMap, "COMBO_DEDXCUT:");
0112 ```
0113
0114 ##### **JANA2**
0115 In JANA2 this has been renamed to `FilterParameters` but the functionality is the same.
0116 Note that this method is not on `JApplication` directly; you have to obtain the parameter manager like so:
0117
0118 ```cpp
0119 //gets all parameters with this filter at the beginning of the key
0120 GetApplication()->GetJParameterManager()->FilterParameters(locParameterMap, "COMBO_DEDXCUT:");
0121 ```
0122
0123
0124 ## DGeometry
0125 #### Getting DGeometry
0126
0127 ##### **JANA1**
0128 ###### Using japp
0129 ```cpp
0130 #include "DANA/DApplication.h"
0131 #include "HDGEOMETRY/DGeometry.h"
0132
0133 DApplication* dapp=dynamic_cast<DApplication*>(japp);
0134 const DGeometry *dgeom = dapp->GetDGeometry(runnumber);
0135 ```
0136
0137 ###### Using eventLoop
0138
0139 ```cpp
0140 #include "DANA/DApplication.h"
0141 #include "HDGEOMETRY/DGeometry.h"
0142
0143 DGeometry *locGeom = dApplication ? dApplication->GetDGeometry(eventLoop->GetJEvent().GetRunNumber()) : NULL;
0144 ```
0145
0146 ##### **JANA2**
0147 In JANA2, you obtain the `DGeometryManager` from the `JApplication` and from there you use the run number to obtain the corresponding `DGeometry`:
0148
0149 ```cpp
0150 #include "HDGEOMETRY/DGeometry.h"
0151
0152 auto runnumber = event->GetRunNumber();
0153 auto app = event->GetJApplication();
0154 auto geo_manager = app->GetService<DGeometryManager>();
0155 auto geom = geo_manager->GetDGeometry(runnumber);
0156 ```
0157
0158 To reduce the boilerplate, we've provided a handy helper function, `DEvent::GetDGeometry()`, that does all of these steps for you:
0159
0160 ```cpp
0161 #include "DANA/DEvent.h"
0162
0163 DGeometry *locGeometry = DEvent::GetDGeometry(locEvent);
0164 ```
0165
0166 You should call `GetDGeometry` from `JFactory::BeginRun` or `JEventProcessor::BeginRun`.
0167
0168
0169 ## Calibration
0170 #### Accessing Calibration Data - `GetCalib`
0171 ##### **JANA1**
0172
0173 ```cpp
0174 locEventLoop->GetCalib(locTOFParmsTable.c_str(), tofparms);
0175 ```
0176
0177 ##### **JANA2**
0178 Analogously to `DGeometry`, you obtain the calibrations by obtaining the `JCalibrationManager` from `JApplication::GetService<>()` and then loading the calibration object corresponding to the event's run number. We recommend you use `DEvent::GetCalib` to avoid this boilerplate. You should call this from your `BeginRun` callback.
0179
0180 ```cpp
0181 #include "DANA/DEvent.h"
0182
0183 DEvent::GetCalib(event, locTOFParmsTable.c_str(), tofparms);
0184 ```
0185
0186 In principle, the calibrations could also be keyed off of event number intervals, in which case you should call it from `Process` and pass the event number as well:
0187
0188 ```cpp
0189 #include <JANA/JEvent.h>
0190 #include <JANA/Calibrations/JCalibrationManager.h>
0191
0192 auto event_number = event->GetEventNumber();
0193 auto run_number = event->GetRunNumber();
0194
0195 auto app = GetApplication();
0196 auto calibration = app->GetService<JCalibrationManager>()->GetJCalibration(run_number);
0197 calibration->Get("BCAL/mc_parms", bcalparms, event_number)
0198 ```
0199
0200
0201 ## Status Bit
0202 #### Accessing Status Bit - `GetStatusBit`
0203
0204 ##### **JANA1**
0205
0206 ```cpp
0207 locEventLoop->GetJEvent().GetStatusBit(kSTATUS_PHYSICS_EVENT)
0208 ```
0209
0210 ##### **JANA2**
0211 Status bits are no longer an event member variable. Instead, they are inserted and retrieved just like the other collections:
0212
0213 ```cpp
0214 #include "DANA/DStatusBits.h"
0215
0216
0217 locEvent->GetSingle<DStatusBits>()->GetStatusBit(kSTATUS_PHYSICS_EVENT)
0218
0219 // or, for a little bit more safety:
0220
0221 locEvent->GetSingleStrict<DStatusBits>()->GetStatusBit(kSTATUS_REST);
0222 ```
0223
0224
0225 ## Magnetic Field
0226 #### Getting Magnetic Field - `GetBField`
0227
0228 ##### **JANA1**
0229
0230 ```cpp
0231 #include "DANA/DApplication.h"
0232
0233 dApplication = dynamic_cast<DApplication*>(locEventLoop->GetJApplication());
0234 dMagFMap= dApplication->GetBfield(locEventLoop->GetJEvent().GetRunNumber());
0235
0236 ```
0237 ##### **JANA2**
0238 In JANA2, the magnetic field map is a resource handled analogously to `DGeometry` and `JCalibrationManager`. Thus, we recommend obtaining the
0239 field map by calling `DEvent::GetBField(event)` from inside `BeginRun`:
0240
0241 ```cpp
0242 #include "DANA/DEvent.h"
0243
0244 dMagneticFieldMap = DEvent::GetBfield(locEvent);
0245 ```
0246
0247
0248 ## Get Functions
0249 ### JObject Getters
0250
0251 #### 1. `GetSingleT`
0252
0253 `GetSingleT` has been replaced with `GetSingle`. Templated methods no longer have a `T` suffix; templated classes (such as `JFactoryT`) still do.
0254 The new `GetSingle` returns a pointer rather than updating an out parameter. If there isn't exactly one associated item of that type, it will return
0255 `nullptr`.
0256
0257 ##### **JANA1**
0258
0259 Was present in JANA1
0260
0261
0262 ##### **JANA2**
0263
0264 No longer available in JANA2; use ```GetSingle()``` instead
0265
0266
0267 #### 2. `GetSingle`
0268 ##### **JANA1**
0269
0270 ```cpp
0271 // Pass by reference
0272 // Set passed param equal to pointer to object
0273 const Df250PulsePedestal* PPobj = NULL;
0274 digihit->GetSingle(PPobj);
0275 ```
0276
0277 ##### **JANA2**
0278 ```cpp
0279 // Template function
0280 // Return pointer to object
0281 auto PPobj = digihit->GetSingle<Df250PulsePedestal>();
0282 ```
0283
0284
0285 #### 3. `Get`
0286
0287 Similarly to `GetSingle`, `Get` returns a vector rather than updating an out parameter.
0288 ##### **JANA1**
0289
0290 ```cpp
0291 // Pass by Reference
0292 vector<const DBCALUnifiedHit*> assoc_hits;
0293 point.Get(assoc_hits);
0294 ```
0295
0296 ##### **JANA2**
0297 ```cpp
0298 // Templated Function
0299 // Return value
0300 vector<const DBCALUnifiedHit*> assoc_hits = point.Get<DBCALUnifiedHit>();
0301 ```
0302 ### JEvent Getters
0303
0304
0305 #### 1. `GetSingle`
0306 ##### **JANA1**
0307
0308 ```cpp
0309 // Pass by Reference,
0310 // passed param got assigned pointer to object
0311
0312 const DTTabUtilities* locTTabUtilities = NULL;
0313 loop->GetSingle(locTTabUtilities);
0314 ```
0315
0316 ##### **JANA2**
0317 ```cpp
0318 // Return the pointer to object based on template type
0319
0320 const DTTabUtilities* locTTabUtilities = event->GetSingle<DTTabUtilities>();
0321 ```
0322
0323 #### 2. `Get`
0324 ##### **JANA1**
0325
0326 ```cpp
0327 // Pass by Reference
0328 vector<const DBCALShower*> showers;
0329 loop->Get(showers, "IU");
0330 ```
0331
0332 ##### **JANA2**
0333 ```cpp
0334 // JANA1 Get is still available but will be deprecated soon
0335 // So better to use the one given below
0336
0337 // Templated function
0338 // Return value
0339 auto showers = event->Get<DBCALShower>("IU");
0340 ```
0341
0342 ## **JEventSource**
0343 ### Key Differences
0344 #### **1. Type name and Resource name
0345
0346 JEventSources are identified by both a type name, e.g. "JEventSource_EVIO", and a resource name, e.g. "./hd_rawdata_123456_000.evio". JANA2 handles both of these differently than JANA1.
0347
0348 In JANA1, the user was required to provide the type name manually by providing two callbacks:
0349 ```c++
0350 virtual const char* className();
0351 static const char* static_className();
0352 ```
0353
0354 In JANA2, the class name is simply a member variable on the `JEventSource` base class, which the user may access via getters and setters:
0355 ```c++
0356 void SetTypeName(std::string type_name);
0357 std::string GetTypeName() const;
0358 ```
0359 Note that `JEventSourceGeneratorT` will automatically populate the type name. If a custom generator is being used, or no generator is used at all (e.g. for test cases), `SetTypeName()` should be called from inside the `JEventSource` constructor, just like with the other components.
0360
0361 The resource name has similarly evolved.
0362 In JANA1, the resource name was always passed as a constructor argument and later accessed using `inline const char* GetSourceName()`. In JANA2, the resource name is a member variable accessed by `SetResourceName(std::string)` and `std::string GetResourceName() const`. While JANA2 still optionally accepts the resource name as a constructor argument for backwards compatibility, this is no longer preferred and will eventually be deprecated in favor of having `JEventSources` be default-constructible. `JEventSourceGeneratorT` already supports both constructor styles, and will automatically populate the resource name just like the type name, so the user shouldn't need to manually call `SetResourceName()`.
0363
0364
0365 #### **2. Event Retrieval (`GetEvent` & `Emit`)**
0366
0367 In JANA1, populating and emitting a fresh event into the stream was done using `GetEvent`, which returned a `jerror_t` code to indicate success or failure.
0368
0369 In JANA2, `jerror_t` has been removed completely, and the `GetEvent` callback has been replaced. JANA2 supports two new callback signatures, with different error-handling approaches. JANA2 will choose which callback to use based off the `callbackStyle` flag. For JEventSources, the available callback styles are `ExpertMode` and `LegacyMode`.
0370 The purpose of the callback style flag is to enable smooth, gradual migrations in the future: components can opt-in to using new features on their own timetable without
0371 having to update everything everywhere.
0372
0373 1. **`JEventSource::Result Emit(JEvent &event)`** – This is the preferred replacement for `GetEvent()`. It returns a `Result` enum with the following values: `Success` (indicating that a fresh event was successfully read), `FailureTryAgain` (indicating that no event was found, but more may be coming later), or `FailureFinished` (indicating that the file has or stream has run out of events and is ready to close). To tell JANA2 to use `Emit`, set the callback style to `ExpertMode` by calling `SetCallbackStyle(CallbackStyle::ExpertMode)` in the constructor.
0374
0375 2. `GetEvent(std::shared_ptr<JEvent> event)` – This callback signature will be deprecated in the near future, and so should not be used for new code. However, we are including it here for completeness. This method returns `void` and signals different statuses by throwing exceptions instead of returning an error code. It throws a `RETURN_STATUS` enum value, which includes `kNO_MORE_EVENTS`, `kBUSY`, `kTRY_AGAIN`, `kERROR`, or `kUNKNOWN`. This callback will be called by default, or if you set `SetCallbackStyle(CallbackStyle::LegacyMode)` in the `JEventSource` constructor.
0376
0377 | **Aspect** | **JANA1** | **JANA2** |
0378 | ------------------------ | -------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
0379 | **`GetEvent`** | `GetEvent(JEvent &event)` returns a `jerror_t` error code (e.g., `NOERROR`, `NO_MORE_EVENTS_IN_SOURCE`). | `GetEvent(std::shared_ptr<JEvent> event)` returns `void` and signals different statuses by throwing `RETURN_STATUS` enum values as exceptions. |
0380 | **Recommended - `Emit`** | _Not available._ | `Emit(JEvent &event)` provides an alternative way to retrieve events. Instead of throwing an exception, it returns one of `Result` enum values to show status. |
0381
0382 #### **3. `GetObjects` Implementation**
0383 JANA1’s `GetObjects` returned a `jerror_t`.
0384 JANA2 replaces this with a `bool` return type. Never return a `jerror_t`, as the compiler may mistakenly perceive it as `true` when the intended meaning is `false`. Always return `true` if objects are found and `false` otherwise.
0385
0386 | **Aspect** | **JANA1** | **JANA2** |
0387 | ----------------------------- | ------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
0388 | **GetObjects Implementation** | `jerror_t GetObjects(jana::JEvent &event, jana::JFactory_base *factory);` | `bool GetObjects(const std::shared_ptr<const JEvent> &event, JFactory* factory) override;` `bool` (return `true` if objects found, otherwise `false`). |
0389
0390 #### **4. Enabling `GetObjects` Call**
0391 In **JANA1**, `GetObjects` was always called, leading to unnecessary performance overhead.
0392 In **JANA2**, `GetObjects` is **disabled by default**. If the source file contains objects that should be used instead of being generated by factories, enable it in the event source constructor:
0393
0394 ```cpp
0395 EnableGetObjects(true);
0396 ```
0397
0398 |**Aspect**|**JANA1**|**JANA2**|
0399 |---|---|---|
0400 |**Enabling `GetObjects` Call**|Called by default for every event.|Disabled by default. Must be enabled with `EnableGetObjects(true)`.|
0401
0402 #### **5. Calling `FinishEvent`**
0403 In **JANA1**, `FreeEvent` was always called automatically after an event was processed, but this required acquiring/releasing locks, adding performance overhead. In **JANA2**, `FinishEvent` replaces `FreeEvent` and is **disabled by default** for efficiency. If additional logic should run at the end of each event, enable it manually in the event source constructor:
0404
0405 ```cpp
0406 EnableFinishEvent(true);
0407 ```
0408
0409 |**Aspect**|**JANA1**|**JANA2**|
0410 |---|---|---|
0411 |**Calling `FinishEvent`**|`FreeEvent` was always called automatically.|`FinishEvent` is disabled by default to improve performance.|
0412
0413 #### 6. Resource lifetimes (`Open()` and `Close()`)
0414
0415 In **JANA1**, the initialization of parameters and opening of the file or socket was done inside the constructor, and the closing of the file or socket was done inside the destructor. In **JANA2**, the lifecycle is **explicitly managed** using the `Init()`, `Open()` and `Close()` callbacks:
0416
0417 | **Aspect** | **JANA1** | **JANA2** |
0418 | -------------------- | --------------------------- | ---------------------------------------------------------------------------- |
0419 | **Initialization** | Handled in the constructor. | `Init()` should be used for obtaining parameters and services. |
0420 | **Opening a Source** | Handled in the constructor. | `Open()` is called when JANA is ready to accept events from the event source |
0421 | **Closing a Source** | Handled in the destructor. | `Close()` is called when the source is done processing events. |
0422
0423 These methods allow better resource management by ensuring that the event source is properly opened before processing events and properly cleaned up afterwards.
0424
0425 ##### **Example Usage in JANA2**
0426 ```cpp
0427 void JEventSource_Sample::Open() {
0428 // Initialize resources (e.g., open files, set up connections)
0429 }
0430
0431 void JEventSource_Sample::Close() {
0432 // Release resources (e.g., close files, disconnect)
0433 }
0434 ```
0435
0436
0437 ### **JEventSource Header Files**
0438 ##### **JANA1**
0439 ```cpp
0440 #ifndef _JEventSource_Sample_
0441 #define _JEventSource_Sample_
0442
0443 #include <JANA/jerror.h>
0444 #include <JANA/JApplication.h>
0445 #include <JANA/JEventSource.h>
0446 #include <JANA/JEvent.h>
0447 #include <JANA/JFactory.h>
0448 #include <JANA/JStreamLog.h>
0449
0450 class JEventSource_Sample: public jana::JEventSource {
0451 public:
0452 JEventSource_Sample(const char* source_name);
0453 virtual ~JEventSource_Sample();
0454
0455 virtual const char* className(void) { return static_className(); }
0456 static const char* static_className(void) { return "JEventSource_Sample"; }
0457
0458 jerror_t GetEvent(JEvent &event);
0459 void FreeEvent(JEvent &event);
0460 jerror_t GetObjects(JEvent &event, jana::JFactory_base *factory);
0461 };
0462
0463 #endif // _JEventSource_Sample_
0464 ```
0465 ##### **JANA2**
0466 ```cpp
0467 #pragma once
0468
0469 #include <JANA/JApplication.h>
0470 #include <JANA/JEventSource.h>
0471 #include <JANA/JEvent.h>
0472 #include <JANA/JFactory.h>
0473 #include <JANA/Compatibility/JStreamLog.h>
0474
0475 class JEventSource_Sample : public JEventSource {
0476 public:
0477 JEventSource_Sample(std::string resource_name) {
0478 SetTypeName(NAME_OF_THIS);
0479 SetCallbackStyle(CallbackStyle::ExpertMode);
0480 EnableGetObjects(true);
0481 EnableFinishEvent(true);
0482 }
0483 virtual ~JEventSource_Sample();
0484
0485 void Init() override;
0486 void Open() override;
0487 void Close() override;
0488 void FinishEvent(JEvent& event) override;
0489 Result Emit(JEvent& event) override;
0490 bool GetObjects(const std::shared_ptr<const JEvent>& event, JFactory* factory) override;
0491 };
0492 ```
0493
0494 ## JEventProcessor
0495 ### JEventProcessor Header File
0496
0497 `JEventProcessors` in JANA2 have a similar feel to JANA1. The key differences are:
0498
0499 1. The names and type signatures of the callbacks have changed
0500 2. The event number and run number now live on the JEvent object rather than as separate arguments
0501 3. JANA2 doesn't use `jerror_t` anywhere for several reasons: there's too many options to exhaustively check, most
0502 error codes don't apply to JEventProcessors, there's no clear indication which error codes represent failure conditions,
0503 and no reasonable strategy JANA can take if a failure is reached other than a premature exit. Thus the callbacks return
0504 void.
0505 4. If a failure condition is reached in user code, the user should throw a `JException` with a detailed message. JANA will
0506 add additional context information (such as the component name, callback, plugin, and backtrace), log everything, and shut
0507 down cleanly.
0508 5. The user no longer provides a `className` callback. Instead, they call `SetTypeName(NAME_OF_THIS);` from the constructor.
0509
0510 ##### JANA1
0511
0512 ```cpp
0513 #ifndef _JEventProcessor_myplugin_
0514 #define _JEventProcessor_myplugin_
0515
0516 #include <JANA/JApplication.h>
0517 #include <JANA/JFactory.h>
0518 #include <JANA/JEventProcessor.h>
0519 using namespace jana;
0520
0521
0522 class JEventProcessor_myplugin : public jana::JEventProcessor{
0523 public:
0524 JEventProcessor_myplugin();
0525 ~JEventProcessor_myplugin();
0526 const char* className(void){return "JEventProcessor_myplugin";}
0527
0528 private:
0529 jerror_t init(void);
0530 jerror_t brun(jana::JEventLoop *eventLoop, int32_t runnumber);
0531 jerror_t evnt(jana::JEventLoop *eventLoop, uint64_t eventnumber);
0532 jerror_t erun(void);
0533 jerror_t fini(void);
0534
0535 };
0536
0537 #endif // _JEventProcessor_myplugin_
0538 ```
0539
0540 ##### JANA2
0541
0542 ```cpp
0543 #ifndef _JEventProcessor_myplugin_
0544 #define _JEventProcessor_myplugin_
0545 #include <JANA/JEventProcessor.h>
0546
0547 class JEventProcessor_myplugin : public JEventProcessor {
0548
0549 public:
0550 JEventProcessor_myplugin() {
0551 SetTypeName(NAME_OF_THIS);
0552 }
0553 ~JEventProcessor_myplugin() = default;
0554
0555 private:
0556 void Init() override;
0557 void BeginRun(const std::shared_ptr<const JEvent>& event) override;
0558 void Process(const std::shared_ptr<const JEvent>& event) override;
0559 void EndRun() override;
0560 void Finish() override;
0561 };
0562
0563 #endif // _JEventProcessor_myplugin_
0564 ```
0565
0566 ## JObject
0567 ### JObject Header File
0568
0569
0570 `JObjects` in JANA2 are also conceptually similar to their JANA1 counterparts, with a
0571 syntax refresh aimed at future extensibility. The `toStrings` callback has been
0572 replaced with a `Summarize` callback as shown below. Note that in JANA2, data model classes
0573 do not need to inherit from `JObject` anymore - `JObject` merely provides clean, user-specified formatting,
0574 and convenient simple tracking of object associations. JANA2 also supports using [PODIO](https://github.com/AIDASoft/podio)
0575 based data models, which provide free serialization/deserialization, a first-class Python interface, automatic
0576 memory management and immutability guarantees, and relational object associations.
0577
0578 ##### JANA1
0579 ```cpp
0580 #include <JANA/JObject.h>
0581 #include <JANA/JFactory.h>
0582
0583 using namespace jana;
0584
0585 class DCereHit: public JObject {
0586 public:
0587
0588 JOBJECT_PUBLIC(DCereHit);
0589 int sector;
0590 float pe;
0591 float t;
0592
0593 void toStrings(vector<pair<string, string> >&items) const {
0594 AddString(items, "sector", "%d", sector);
0595 AddString(items, "pe", "%1.3f", pe);
0596 AddString(items, "t", "%1.3f", t);
0597 }
0598 };
0599 ```
0600
0601 ##### JANA2
0602
0603 ```cpp
0604 #include <JANA/JObject.h>
0605
0606 class DCereHit: public JObject {
0607 public:
0608
0609 JOBJECT_PUBLIC(DCereHit);
0610 int sector;
0611 float pe;
0612 float t;
0613
0614 void Summarize(JObjectSummary& summary) const override {
0615 summary.add(sector, "sector", "%d");
0616 summary.add(pe, "pe", "%1.3f");
0617 summary.add(t, "t", "%1.3f");
0618 }
0619 };
0620 ```
0621 ### JObject ID Handling
0622
0623 In JANA1, JObjects provided an `id` field. However it was left up to the user how to set and use it. Because JANA can't guarantee
0624 that it is set reliably or consistently, it is fundamentally part of the data model and not part of the framework. Thus, JANA2
0625 no longer provides a built-in object id. If needed, users are welcome to add their own `id` field to their data model classes and
0626 establish a convention for how and when it gets set. For reliable, automatic object IDs for all data model classes, consider using PODIO.
0627
0628
0629 ##### **JANA1**
0630 ```cpp
0631 // JANA1 JObject had a data member id
0632
0633 DBCALShower *shower = new DBCALShower;
0634 shower->id = id++;
0635 ```
0636 ##### **JANA2**
0637
0638 ```cpp
0639 // id data member does not exist in JObject anymore in JANA2
0640
0641 DBCALShower *shower = new DBCALShower;
0642 shower->id = id++; // Compiler error
0643 ```
0644
0645 Similarly, the `JObject::oid_t` type has been removed from JANA2 as well. If you need it, it lives on in the halld_recon codebase:
0646
0647 ```cpp
0648 #include "DANA/DObjectID.h"
0649
0650 oid_t // Not inside JObject anymore!
0651 ```
0652
0653 ## JFactory
0654 ### Transition from JFactory to JFactoryT
0655 ##### **JANA1**
0656 In JANA1, `JFactory_base` was a common factory base class, and `JFactory` was a template that inherits from `JFactory_base` and adds functionality specific to the type of the factory's output collection.
0657 ##### **JANA2**
0658 In JANA2, the base class was renamed to `JFactory`, and the template was renamed to `JFactoryT`. JANA2 adds some new functionality, but the old functionality is largely consistent with JANA1.
0659
0660 The syntax differences between JANA1 and JANA2 `JFactory`s' are consistent with those for `JEventProcessor`s.
0661
0662 1. The names and type signatures of the callbacks have changed
0663 2. The event number and run number now live on the JEvent object rather than as separate arguments
0664 3. JANA2 doesn't use `jerror_t` anywhere for several reasons: there's too many options to exhaustively check, most
0665 error codes don't apply to JEventProcessors, there's no clear indication which error codes represent failure conditions,
0666 and no reasonable strategy JANA can take if a failure is reached other than a premature exit. Thus the callbacks return
0667 void.
0668 4. If a failure condition is reached in user code, the user should throw a `JException` with a detailed message. JANA will
0669 add additional context information (such as the component name, callback, plugin, and backtrace), log everything, and shut
0670 down cleanly.
0671 5. The user no longer provides a `className` callback. Instead, they call `SetTypeName(NAME_OF_THIS);` from the constructor.
0672
0673 Another important difference is how factory tags are set. In JANA1, the user provides a `Tag()` callback, whereas in JANA2,
0674 the user sets the tag by calling `SetTag()` from the constructor. The user can retrieve the factory tag by calling `GetTag()`.
0675
0676 One important semantic difference is that in JANA1, there is always one factory set assigned to each thread, whereas in JANA2,
0677 there is one factory set for each event in flight. The number of in-flight events is a parameter controlled separately
0678 from the thread count. This is important for ensuring that there is always work for threads to do when running
0679 multi-level processing topologies. Another consequence of this design is that factories don't belong to just one thread and hence
0680 shouldn't reference thread-local variables - instead, one thread can pop an event from a queue, process it, and push it to a
0681 different queue, where it could later be picked up by a different thread. Importantly, however, only one thread has access to any
0682 given JEvent and its corresponding factory set at any time, so you don't need to worry about thread safety in JFactories.
0683
0684 ### Factory Header File
0685
0686 ##### JANA1
0687
0688 ```cpp
0689 #ifndef _myfactory_factory_
0690 #define _myfactory_factory_
0691
0692 #include <JANA/JFactory.h>
0693 #include "myobject.h"
0694
0695 class myfactory_factory : public jana::JFactory<myobject> {
0696
0697 public:
0698 myfactory_factory() = default;
0699 ~myfactory_factory() = default;
0700
0701 const char* Tag() { return "MyTag"; }
0702
0703 private:
0704 jerror_t init(void);
0705 jerror_t brun(jana::JEventLoop *eventLoop, int32_t runnumber);
0706 jerror_t evnt(jana::JEventLoop *eventLoop, uint64_t eventnumber);
0707 jerror_t erun(void);
0708 jerror_t fini(void);
0709 };
0710
0711 #endif
0712 ```
0713
0714 ##### JANA2
0715
0716 ```cpp
0717 #ifndef _thirdFacTest_factory_
0718 #define _thirdFacTest_factory_
0719
0720 #include <JANA/JFactoryT.h>
0721 #include "myobject.h"
0722
0723 class thirdFacTest_factory : public JFactoryT<myobject> {
0724 public:
0725 thirdFacTest_factory() {
0726 SetTag("MyTag");
0727 }
0728 ~thirdFacTest_factory() = default;
0729
0730 private:
0731 void Init() override;
0732 void BeginRun(const std::shared_ptr<const JEvent>& event) override;
0733 void Process(const std::shared_ptr<const JEvent>& event) override;
0734 void EndRun() override;
0735 void Finish() override;
0736 };
0737
0738 #endif
0739 ```
0740
0741 ### Registering a New Factory
0742
0743 In JANA1, the user creates a `JFactoryGenerator` with a `GenerateFactories()` callback. Within this callback,
0744 the user instantiates new factories and adds them to a `JEventLoop`. (In `halld_recon`, there is a `DFactoryGenerator`
0745 which instantiates factories for all fundamental detector plugins, calling each plugin's corresponding
0746 `$DETECTOR_init()` function.)
0747
0748 In JANA2, the user is still free to create their own `JFactoryGenerator`. It's syntax has been modified (notably,
0749 `GenerateFactories()` provides a `JFactorySet` argument that the user adds the factories to), but the core concepts
0750 are the same. However, there is now also a `JFactoryGeneratorT` utility which reduces the boilerplate. As long
0751 as the factory is default constructible, the user merely needs to pass the factory class as a template argument to
0752 `JFactoryGeneratorT`, and JANA will do the rest of the work. JANA2 is perfectly fine with users passing a single
0753 `JFactoryGenerator` that instantiates every single factory in the system, but there are future benefits if users
0754 pass separate `JFactoryGeneratorT`s for each factory instead.
0755
0756
0757 ##### **JANA1**
0758
0759 ```cpp
0760 #include <JANA/JApplication.h>
0761 #include "JFactoryGenerator_myfactory.h"
0762 #include "myfactory.h"
0763
0764 using namespace jana;
0765
0766 extern "C" {
0767 void InitPlugin(JApplication *app) {
0768 InitJANAPlugin(app);
0769 app->AddFactoryGenerator(new JFactoryGenerator_myfactory());
0770 }
0771 } // "C"
0772 ```
0773
0774 ##### **JANA2**
0775
0776 ```cpp
0777 #include <JANA/JApplication.h>
0778 #include <JANA/JFactoryGenerator.h>
0779 #include "myfactory.h"
0780
0781 extern "C" {
0782 void InitPlugin(JApplication *app) {
0783 InitJANAPlugin(app);
0784 app->Add(new JFactoryGeneratorT<my_factory>());
0785 }
0786 } // "C"
0787 ```
0788
0789 ### Getting All Factories
0790
0791 Sometimes it is necessary to retrieve all factories that produce objects of a given type. In
0792 JANA1 this was done by retrieving all factories and doing a `dynamic_cast`. In JANA2 there's a
0793 dedicated method for this, `GetFactoryAll`. (Note that this will retrieve the factories without
0794 automatically running them!). JANA2 also supports retrieving all objects of type `T` from all
0795 factories using `GetAll()` and retrieving all objects descended from parent type `T`
0796 (e.g. `JObject` or `TObject`) using `GetAlllChildren()`.
0797
0798 ##### **JANA1**
0799
0800 ```cpp
0801 vector<JFactory_base*> locFactories = locEventLoop->GetFactories();
0802 // Cast JFactory_base to particular factory type
0803 JFactory<DReaction>* locFactory = dynamic_cast<JFactory<DReaction>*>(locFactories[0]);
0804 ```
0805
0806 ##### **JANA2**
0807
0808 ```cpp
0809 // Retrieve all factories producing T directly
0810 vector<JFactoryT<DReaction>*> locFacs = locEvent->GetFactoryAll<DReaction>();
0811 ```
0812
0813 ### Saving Created Object(s) to Factory
0814
0815 When writing a factory, the user creates some data objects inside `Process()` and
0816 then needs to pass them back to JANA. In JANA1, this was done by modifying the
0817 `_data` member variable directly. In JANA2, we prefer using a dedicated setter method.
0818 For the sake of porting GlueX without having to rewrite certain complex factories,
0819 we've left the member variable `protected`, though the member variable has been
0820 renamed to `mData`.
0821
0822 ##### _Single Object_
0823 ###### **JANA1**
0824
0825 ```cpp
0826 _data.push_back(locAnalysisResults);
0827 ```
0828
0829 ###### **JANA2**
0830
0831 ```cpp
0832 Insert(locAnalysisResults);
0833
0834 // Or (less preferred)
0835 mData.push_back(locAnalysisResults);
0836 ```
0837
0838 ##### _Array of Objects_
0839
0840 ```cpp
0841 std::vector<Hit*> results;
0842 results.push_back(new Hit(...));
0843 ```
0844
0845 ###### **JANA1**
0846
0847 ```cpp
0848 for (auto hit: results){
0849 _data.push_back(hit);
0850 }
0851 ```
0852
0853 ###### **JANA2**
0854
0855 ```cpp
0856 Set(results)
0857 ```
0858
0859 ### **Setting Factory Flag**
0860 In JANA1, factory flag was set by calling `SetFactoryFlag(FLAG_NAME)` inside the factory constructor. The available flags were:
0861
0862 ```cpp
0863 enum JFactory_Flags_t {
0864 JFACTORY_NULL = 0x00,
0865 PERSISTANT = 0x01, // Misspelling of "PERSISTENT"
0866 WRITE_TO_OUTPUT = 0x02,
0867 NOT_OBJECT_OWNER = 0x04
0868 };
0869 ```
0870
0871 JANA2 retains the same approach but introduces an additional flag while correcting the spelling of `PERSISTANT`:
0872
0873 ```cpp
0874 enum JFactory_Flags_t {
0875 JFACTORY_NULL = 0x00,
0876 PERSISTENT = 0x01, // Corrected spelling
0877 WRITE_TO_OUTPUT = 0x02,
0878 NOT_OBJECT_OWNER = 0x04,
0879 REGENERATE = 0x08 // New flag
0880 };
0881 ```
0882 #### **Key Differences**
0883 ##### **1. `REGENERATE` – Forcing the Factory to Regenerate Objects**
0884 In JANA2, the `REGENERATE` flag prevents JANA from searching for objects in the input file, replicating the behavior of `use_factory = 1` in JANA1.
0885 ###### **JANA1:**
0886 ```cpp
0887 DEventWriterROOT_factory_ReactionEfficiency() {
0888 use_factory = 1;
0889 };
0890 ```
0891 ###### **JANA2:**
0892 ```cpp
0893 DEventWriterROOT_factory_ReactionEfficiency() {
0894 SetRegenerateFlag(REGENERATE);
0895 };
0896 ```
0897
0898 Alternatively, you can enable the `REGENERATE` flag using a boolean value:
0899
0900 ```cpp
0901 DEventWriterROOT_factory_ReactionEfficiency() {
0902 SetRegenerateFlag(true);
0903 };
0904 ```
0905
0906 ##### **2. `PERSISTENT` – Making Factory-Generated Objects Persistent**
0907 In JANA1, objects were made persistent by calling `SetFactoryFlag(PERSISTANT)`. JANA2 corrects the spelling mistake, renaming it to `PERSISTENT`, while maintaining the same core functionality. However, there is a key difference in how persistent objects are handled:
0908 - **JANA1:** The destructors of persistent objects are called automatically when the process terminates.
0909 - **JANA2:** The destructors of persistent objects are never called automatically, meaning any logic inside them will not execute unless the objects are explicitly deleted by the user. Therefore, if you set the `PERSISTENT` flag, you must manually delete these objects inside the factory’s `Finish()` method to prevent memory leaks.
0910
0911 ```cpp
0912 void Finish() {
0913 for (auto locInfo : mData) {
0914 delete locInfo;
0915 }
0916 mData.clear();
0917 }
0918 ```
0919
0920 ## JEvent
0921 ### Transition from JEventLoop to JEvent
0922 ##### **JANA1**
0923 In JANA1, all processing operated on a `JEventLoop` object. In JANA2, this has been changed to `JEvent`.
0924 Conceptually, a `JEvent` is just a container for data that can be processed as a discrete unit, indepedently from the rest
0925 of the stream (this usually correspondings to a physics event, but also potentially a timeslice, block, subevent, etc). This includes the
0926 event number, run number, all data read from the event source, all data created by factories so far, and all of
0927 the factory state necessary to generate additional data belonging to the same context. The factories themselves are managed by a `JFactorySet`
0928 which is one-to-one with and owned by the JEvent.
0929
0930 ### Getting the Run Number
0931 ##### **JANA1**
0932 ```cpp
0933 run_number = locEventLoop->GetJEvent().GetRunNumber());
0934 ```
0935 ##### **JANA2**
0936 ```cpp
0937 locEvent->GetRunNumber()
0938 ```
0939
0940 #### Getting the Event Number
0941 ##### **JANA1**
0942
0943 ```cpp
0944 run_number = locEventLoop->GetJEvent().GetEventNumber());
0945 ```
0946 ##### **JANA2**
0947
0948 ```cpp
0949 locEvent->GetEventNumber()
0950 ```
0951
0952 ## Acquiring Locks
0953
0954 JANA1 required the user to manually acquire and hold locks when accessing to shared resources in a JEventProcessor.
0955 JANA2 offers a different interface which handles all locks internally. However, using this new callback interface
0956 would require restructuring the existing `JEventProcessor` code. When migrating from JANA1 to JANA2 it
0957 is much safer to avoid making such deep changes, at least initially. The old-style user-managed locks can be migrated
0958 to JANA2 as-is with one minor change: the various lock helper methods have been moved from `JApplication` to `JLockService`.
0959
0960
0961 ### ROOT Read/Write locks
0962 ##### JANA1
0963
0964 ```cpp
0965 dActionLock = japp->RootReadLock();
0966 // ...
0967 japp->RootUnLock(locLockName);
0968 ```
0969 ##### JANA2
0970
0971 ```cpp
0972 auto app = GetApplication(); // or event->GetJApplication()
0973 auto lock_svc = app->GetService<JLockService>();
0974
0975 lock_svc->RootReadLock();
0976 // ...
0977 lock_svc->RootUnLock();
0978 ```
0979
0980 To reduce boilerplate, we've added a helper function:
0981
0982 ```cpp
0983 #include "DANA/DEvent.h"
0984
0985 DEvent::GetLockService(locEvent)->RootWriteLock();
0986 DEvent::GetLockService(locEvent)->RootUnLock();
0987 ```
0988
0989 ### Named locks
0990
0991 ##### JANA1
0992
0993 ```cpp
0994 dActionLock = japp->ReadLock(locLockName);
0995 // ...
0996 pthread_rwlock_unlock(dActionLock);
0997 // Or: japp->Unlock(locLockName);
0998 ```
0999
1000 ##### JANA2
1001
1002 ```cpp
1003 auto app = GetApplication(); // or event->GetJApplication()
1004 auto lock_svc = app->GetService<JLockService>();
1005
1006 dActionLock = lock_svc->ReadLock(locLockName);
1007 // ...
1008 pthread_rwlock_unlock(dActionLock);
1009 // Or: lock_svc->Unlock(locLockName);
1010 ```
1011
1012 To reduce boilerplate:
1013
1014 ```cpp
1015 DEvent::GetLockService(locEvent)->ReadLock("app");
1016 DEvent::GetLockService(locEvent)->Unlock("app");
1017 ```
1018 ## Deprecated Headers & Functions
1019
1020 ### Why Do These Warnings Appear?
1021 When building a plugin ported to JANA2, you may see deprecation warnings (deprecated headers etc.). These headers and functions exist in JANA2 only for backward compatibility with JANA1 and are marked as deprecated to discourage their use, as they may be removed in the future.
1022
1023 ### Can These Warnings Be Ignored?
1024 Yes, as long as your plugin compiles without crashes. They don't have any immediate impact on functionality. However, it’s better to update to the latest headers and functions because:
1025 - Deprecated headers and functions may be removed completely in future JANA2 versions.
1026 - Using them can slightly slow down compilation.
1027 ### How to Remove These Warnings?
1028 Replace deprecated headers and functions in your plugin code with alternatives provided in following table:
1029
1030 | **Deprecated** | **Use Instead** |
1031 |--------------------------|---------------------------|
1032 | `#include <JANA/Compatibility/JLockService.h>` | `#include <JANA/Services/JLockService.h>` |
1033 | `#include <JANA/Compatibility/JGeometry.h>` | `#include <JANA/Geometry/JGeometry.h>` |
1034 | `#include <JANA/Calibrations/JLargeCalibration.h>` | `#include <JANA/Calibrations/JResource.h>` |
1035 | `auto *jlargecalib = DEvent::GetJLargeCalibration(event);` | `auto *res = DEvent::GetJResource(event);` |
1036 | `jlargecalib->GetResource(dedx_i_theta_file_name["file_name"]);` | `res->GetResource(dedx_i_theta_file_name["file_name"]);` |
1037 | `JLargeCalibration *jresman;` | `JResource *jresman;` |
1038 | `jresman = calib_svc->GetLargeCalibration(runnumber);` | `jresman = calib_svc->GetResource(runnumber);` |
1039 | `#include <JANA/Compatibility/JGeometryXML.h>` | `#include <JANA/Geometry/JGeometryXML.h>` |
1040 | `#include <JANA/Compatibility/JGeometryManager.h>` | `#include <JANA/Geometry/JGeometryManager.h>` |
1041 | `#include <JANA/Compatibility/JStatusBits.h>` | `#include <JANA/Utils/JStatusBits.h>` |
1042 | `#include <JANA/Compatibility/jerror.h>` | `#include <DANA/jerror.h>` |
1043
1044
1045 ## Rarely Used Features
1046
1047 ### `Unknown` Handling
1048
1049 The enum in `particleType.h` was experiencing a name conflict with a JANA2 enum, so it has been changed
1050 to an enum class.
1051
1052 ##### **JANA1**
1053
1054 ```cpp
1055 //Was a plain enum so could be accessed without any scope resolution operator
1056
1057 #include "particleType.h"
1058
1059 return ((locFirstStep->Get_TargetPID() != Unknown) || (locFirstStep->Get_SecondBeamPID() != Unknown));
1060 ```
1061
1062 ##### **JANA2**
1063 ```cpp
1064 // Is Enum class now so could be accessed like this `Particle_t::Unknown` only
1065
1066 #include "particleType.h"
1067
1068 return ((locFirstStep->Get_TargetPID() != Particle_t::Unknown) || (locFirstStep->Get_SecondBeamPID() != Particle_t::Unknown));
1069 ```