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