Commit 9b0a701a authored by Andrei Muresan's avatar Andrei Muresan
Browse files

Document high-level architecture design

parent 6c3f6e4c
......@@ -44,8 +44,11 @@ shellcheck:
.PHONY: docs
docs:
mkdir -p public/doxygen
mkdir public
doxygen Doxyfile
clean/docs:
rm -rf public
clean:
rm -rf obj bin lib
\ No newline at end of file
rm -rf obj bin lib
......@@ -94,3 +94,4 @@ From inside the container, run `make`.
# Other Documentation
- [How our documentation works](docs/DOCUMENTATION.md)
- [Project Architecture](docs/ARCHITECTURE.md)
# Project Architecture
# Overview
This document aims to explain the project's architecture design along with any major patterns, principles, and decisions involved in its creation.
# High-Level Architecture
**Note:** Not all fields, methods, and relationships are depicted in this diagram. Its purpose is just to give a high-level overview of the system and the major relationships between its subsystems. Refer to the [PlantUML class diagram documentation](https://plantuml.com/class-diagram) to understand the syntax used.
\startuml
!include ../docs/architecture.puml
\enduml
# Subsystems
## Main
The **MAIN** subsystem handles program parameters and orchestrates the other components of the system in a composable fashion. The `RunManager` class acts as a central source of truth for application-wide state and behaviour as per the [Mediator Pattern](https://refactoring.guru/design-patterns/mediator).
## Reader
The **READER** subsystem handles extracting and parsing input event data. The `Reader` implements the [Iterator](https://refactoring.guru/design-patterns/iterator) pattern, exposing a device-agnostic stream of events to the mediator. Device-specific reader classes can be written, and the [Factory](https://refactoring.guru/design-patterns/factory) class returns the implementation matching the runtime configuration.
## Pulse Finding
The **PULSE FINDING** subsystem analyzes channel waveform data and identifies pulses using a specified algorithm. The subsystem implements a [Strategy](https://refactoring.guru/design-patterns/strategy) pattern to allow pulse-finding algorithms to be implemented separately and specified via runtime configuration.
## Pulse Analysis
The **PULSE ANALYSIS** subsystem is responsible for fitting channel pulse data using a specified algorithm. It implements a [Strategy](https://refactoring.guru/design-patterns/strategy) pattern similar to the `PULSE FINDING` for similar reasons.
@startuml
skinParam classFontSize 16
skinParam defaultFontSize 14
left to right direction
package DATA {
class Waveform extends ROOT.TH1D
class Pulse << (S, #9dc3e6) struct >>
class Channel {
+Waveform *wf
+vector<Pulse> pulses
}
class Event {
+vector<Channel> channels
}
Channel --o Waveform
Channel --o Pulse
Channel o-- Event
Event o-- MAIN.RunManager
}
package ROOT {
class TH1D
class TFile
TFile *-- READER.LecroyReader
}
package ROOTANA {
class TMidasFile
TMidasFile *-- READER.V1730Reader
}
package ENUMS {
enum PulseFindingStrategies {
ABC
XYZ
...
}
enum PulseFittingStrategies {
ABC
XYZ
...
}
enum InputDeviceTypes {
V1730
Lecroy
...
}
}
package MAIN {
class RunManager {
+main()
-map<Channel, PulseFindingStrategies> setPulseFindingStrategies(RunConfig config)
-map<Channel, PulseFittingStrategies> setPulseFittingStrategies(RunConfig config)
}
class RunConfig << (S, #9dc3e6) struct >>
RunManager --* RunConfig
RunManager --* READER.Reader
RunManager --> READER.ReaderFactory
RunManager --> PULSE_FINDING.PulseFindingStrategy
RunManager --> PULSE_ANALYSIS.PulseFittingStrategy
}
package READER {
interface Reader {
+Event nextEvent()
+bool hasEvent()
}
class ReaderFactory << static >> {
+{static}Reader createReader(RunConfig config)
}
class V1730Reader implements Reader {
+Event nextEvent()
+bool hasEvent()
}
class LecroyReader implements Reader {
+Event nextEvent()
+bool hasEvent()
}
ReaderFactory --> V1730Reader
ReaderFactory --> LecroyReader
}
package PULSE_FINDING {
interface PulseFindingStrategy {
+{static}vector<Pulse> findPulses(Waveform *wf, RunConfig config)
-{static}Waveform preprocessWaveformData(Waveform *wf, RunConfig config)
}
class XYZPulseFindingStrategy << static >> implements PulseFindingStrategy {
+{static}vector<Pulse> findPulses(Waveform *wf, RunConfig config)
-{static}Waveform preprocessWaveformData(Waveform *wf, RunConfig config)
}
class ABCPulseFindingStrategy << static >> implements PulseFindingStrategy {
+{static}vector<Pulse> findPulses(Waveform *wf, RunConfig config)
-{static}Waveform preprocessWaveformData(Waveform *wf, RunConfig config)
}
}
package PULSE_ANALYSIS {
interface PulseFittingStrategy {
+{static}void fit(Channel *channel, RunConfig config)
-{static}void sortPulses(Channel *channel)
-{static}void refit(Channel *channel, RunConfig config)
}
class XYZPulseFittingStrategy << static >> implements PulseFittingStrategy {
+{static}void fit(Channel *channel, RunConfig config)
-{static}void sortPulses(Channel *channel)
-{static}void refit(Channel *channel, RunConfig config)
}
class ABCPulseFittingStrategy << static >> implements PulseFittingStrategy {
+{static}void fit(Channel *channel, RunConfig config)
-{static}void sortPulses(Channel *channel)
-{static}void refit(Channel *channel, RunConfig config)
}
}
@enduml
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment