88 * This example emulates a simplified event loop where each event produces hit data for one or more
99 * sensitive detectors and stores them into a \ref GEventDataCollection.
1010 *
11- * The \ref GEventDataCollection owns *per-hit* objects (event-level semantics):
12- * - \ref GTrueInfoData: "truth" observables derived from simulation / tracking (energy deposition, positions, times, …)
13- * - \ref GDigitizedData: "digitized" observables produced by electronics/digitization (ADC/TDC-like quantities, readout coords, …)
11+ * The \ref GEventDataCollection owns *per-hit* objects (event-level semantics). For each hit, two
12+ * complementary views may be produced and stored:
13+ * - \ref GTrueInfoData stores simulation-level ("truth") observables derived from tracking
14+ * (energy deposition, step-averaged kinematics, positions, times, provenance labels, ...).
15+ * - \ref GDigitizedData stores electronics-level ("digitized") observables produced by
16+ * detector response and digitization logic (ADC/TDC-like quantities, calibrated values, readout coordinates, ...).
1417 *
1518 * For each event, data are organized as:
1619 * \code
2023 * \endcode
2124 *
2225 * \section event_demo What this example demonstrates
23- * - Creating event containers ( \ref GEventDataCollection::create()) .
24- * - Adding *additional hits* and *additional detectors* to the same event via :
25- * - \ref GEventDataCollection::addDetectorTrueInfoData()
26- * - \ref GEventDataCollection::addDetectorDigitizedData()
27- * - Inspecting the stored data:
26+ * - Creating event containers with the factory \ref GEventDataCollection::create "create()" .
27+ * - Adding *additional hits* and *additional detectors* to the same event with :
28+ * - \ref GEventDataCollection::addDetectorTrueInfoData "addDetectorTrueInfoData()"
29+ * - \ref GEventDataCollection::addDetectorDigitizedData "addDetectorDigitizedData()"
30+ * - Inspecting stored data:
2831 * - per-detector hit counts
29- * - identity strings (\ref GTrueInfoData::getIdentityString, \ref GDigitizedData::getIdentityString)
32+ * - identity strings (\ref GTrueInfoData::getIdentityString "getIdentityString()",
33+ * \ref GDigitizedData::getIdentityString "getIdentityString()")
3034 * - truth and digitized observable maps
31- * - Demonstrating digitized filtering of streaming-readout (SRO) keys:
32- * - \ref GDigitizedData::getIntObservablesMap(int)
33- * - \ref GDigitizedData::getDblObservablesMap(int)
35+ * - Demonstrating filtering of streaming-readout (SRO) keys for digitized data :
36+ * - \ref GDigitizedData::getIntObservablesMap "getIntObservablesMap (int)"
37+ * - \ref GDigitizedData::getDblObservablesMap "getDblObservablesMap (int)"
3438 *
3539 * \section event_threading Threading model
3640 * The example uses a simple work-distribution pattern:
3741 * - A shared atomic counter assigns event numbers.
3842 * - Each worker thread builds independent \ref GEventDataCollection objects.
3943 * - Results are appended to a shared vector under a mutex.
4044 *
41- * \note \ref GEventHeader::create() and the test factories \ref GTrueInfoData::create and
42- * \ref GDigitizedData::create use internal thread-safe counters, so concurrent execution
43- * is supported for this example-style workload.
45+ * \note \ref GEventHeader::create "create()" and the test factories
46+ * \ref GTrueInfoData::create "create()" and \ref GDigitizedData::create "create()"
47+ * use internal thread-safe counters, so concurrent execution is supported for this
48+ * example-style workload.
4449 *
4550 * \section gdata_event_usage Usage
4651 * Build this example together with the GData library components and required GEMC utilities
47- * (logging, options, threads abstraction).
52+ * (logging, options, threads abstraction). Then run it to print a readable dump of each generated
53+ * event container.
4854 *
4955 * \author \n © Maurizio Ungaro
5056 * \author e-mail: ungaro@jlab.org
7076 * \brief Convert a scalar map into a compact, deterministic string for logging.
7177 *
7278 * \details
73- * This helper exists purely for examples/tests: it prints key/value pairs in the
74- * order given by the container (std::map order is lexicographic by key).
79+ * This helper exists purely for examples/tests. It prints key/value pairs in the order given
80+ * by the container.
81+ *
82+ * Determinism note:
83+ * - \c std::map iterates in lexicographic key order, which makes the output stable across runs.
7584 *
7685 * \tparam MapType A map-like type with string keys and printable scalar values.
7786 * \param m The map to stringify.
@@ -96,16 +105,16 @@ static std::string map_to_string(const MapType& m) {
96105 *
97106 * \details
98107 * This performs a deep inspection of the \ref GEventDataCollection structure:
99- * - loops over detectors (sdName)
100- * - prints number of truth hits and digitized hits
108+ * - loops over detectors (\c sdName)
109+ * - prints the number of truth hits and digitized hits
101110 * - for each hit prints identity and observables
102111 *
103- * For digitized data, this also prints both filtered views:
104- * - which=0: non-SRO (physics/content) keys
105- * - which=1: SRO-only keys (crate/slot/channel/timeAtElectronics/chargeAtElectronics)
112+ * For digitized data, this prints both filtered views to demonstrate SRO separation :
113+ * - \c which=0: non-SRO (physics/content) keys
114+ * - \c which=1: SRO-only keys (crate/slot/channel/timeAtElectronics/chargeAtElectronics)
106115 *
107116 * \param edc The event to inspect.
108- * \param log Logger to emit messages to .
117+ * \param log Logger used to emit messages.
109118 */
110119static void dump_event (const std::shared_ptr<GEventDataCollection>& edc, const std::shared_ptr<GLogger>& log) {
111120 log->info (0 , " ------------------------------------------------------------" );
@@ -165,7 +174,7 @@ static void dump_event(const std::shared_ptr<GEventDataCollection>& edc, const s
165174 log->info (0 , " dbl non-SRO: " , map_to_string (dbls_non_sro));
166175 log->info (0 , " dbl SRO: " , map_to_string (dbls_sro_only));
167176
168- // Convenience accessor demo (shows sentinel if missing):
177+ // Convenience accessor demo (shows sentinel if missing).
169178 log->info (0 , " timeAtElectronics() = " , dh->getTimeAtElectronics ());
170179 }
171180 }
@@ -176,15 +185,17 @@ static void dump_event(const std::shared_ptr<GEventDataCollection>& edc, const s
176185 *
177186 * \details
178187 * This performs a few sanity checks that are useful when evolving the library:
179- * - event has at least one detector
180- * - each detector collection has consistent hit vectors ( non-null pointers)
188+ * - the event has at least one detector
189+ * - each detector collection has non-null hit pointers
181190 *
182- * \note This is intentionally non-fatal; it logs diagnostics rather than aborting.
191+ * This is intentionally non-fatal. It logs diagnostics rather than aborting so the example
192+ * can continue printing the full event content for debugging.
183193 *
184194 * \param edc The event to validate.
185195 * \param log Logger instance.
186196 */
187- static void validate_event_structure (const std::shared_ptr<GEventDataCollection>& edc, const std::shared_ptr<GLogger>& log) {
197+ static void validate_event_structure (const std::shared_ptr<GEventDataCollection>& edc,
198+ const std::shared_ptr<GLogger>& log) {
188199 const auto & dcm = edc->getDataCollectionMap ();
189200 if (dcm.empty ()) {
190201 log->info (0 , " VALIDATION: event " , edc->getEventNumber (), " has no detectors (unexpected in this example)." );
@@ -207,9 +218,9 @@ static void validate_event_structure(const std::shared_ptr<GEventDataCollection>
207218 if (!digiHits[i]) log->info (0 , " VALIDATION: detector <" , sdName, " > digitized hit " , i, " is null." );
208219 }
209220
210- // A very common expectation in practice: same number of truth and digitized hits per detector.
211- // This is not guaranteed by the API (you can add one without the other), but it is a useful
212- // check for this demo-style data producer.
221+ // A common expectation in production is matching truth and digitized hit counts per detector.
222+ // This is not enforced by the API (you can add one without the other), but it is a useful
223+ // consistency check for this demo-style producer.
213224 if (truthHits.size () != digiHits.size ()) {
214225 log->info (0 , " VALIDATION: detector <" , sdName, " > truthHits(" , truthHits.size (),
215226 " ) != digitizedHits(" , digiHits.size (), " ) in event " , edc->getEventNumber ());
@@ -221,10 +232,14 @@ static void validate_event_structure(const std::shared_ptr<GEventDataCollection>
221232 * \brief Produce a set of events using multiple worker threads.
222233 *
223234 * \details
224- * Each event is created via \ref GEventDataCollection::create() , then extended to demonstrate:
235+ * Each event is created via \ref GEventDataCollection::create "create()" , then extended to demonstrate:
225236 * - adding additional hits under the same detector key
226237 * - adding a second detector key
227238 *
239+ * Concurrency notes:
240+ * - Each worker produces independent event containers (no shared mutation of events).
241+ * - A mutex is used only when appending thread-local results to the shared output vector.
242+ *
228243 * \param nevents Total number of events to generate.
229244 * \param nthreads Number of worker threads.
230245 * \param gopt Shared options.
@@ -240,7 +255,7 @@ static auto run_simulation_in_threads(int nevents,
240255 std::vector<std::shared_ptr<GEventDataCollection>> collected;
241256 collected.reserve (static_cast <size_t >(nevents));
242257
243- // Thread-safe integer event counter starts at 1.
258+ // Thread-safe integer event counter starts at 1 (local to this example run) .
244259 std::atomic<int > next{1 };
245260
246261 // Pool of threads. (jthread_alias joins on destruction.)
0 commit comments