diff --git a/.github/workflows/mdbook.yml b/.github/workflows/mdbook.yml index bf542a27..550fe698 100644 --- a/.github/workflows/mdbook.yml +++ b/.github/workflows/mdbook.yml @@ -30,7 +30,8 @@ jobs: build: runs-on: ubuntu-latest env: - MDBOOK_VERSION: 0.4.21 + MDBOOK_VERSION: 0.4.36 + MDBOOK_ADMONISH_VERSION: 1.14.0 # need to re-run mdbook-admonish install if updating version steps: - uses: actions/checkout@v4 - name: Install mdBook @@ -38,6 +39,7 @@ jobs: curl --proto '=https' --tlsv1.2 https://sh.rustup.rs -sSf -y | sh rustup update cargo install --version ${MDBOOK_VERSION} mdbook + cargo install --version ${MDBOOK_ADMONISH_VERSION} --locked mdbook-admonish - name: Setup Pages id: pages uses: actions/configure-pages@v4 diff --git a/book.toml b/book.toml index ee8ec509..e6458d34 100644 --- a/book.toml +++ b/book.toml @@ -12,6 +12,7 @@ create-missing = false mathjax-support = true git-repository-url = "https://github.com/LDMX-Software/ldmx-software.github.io/tree/trunk/" edit-url-template = "https://github.com/LDMX-Software/ldmx-software.github.io/edit/trunk/{path}" +additional-css = ["./mdbook-admonish.css"] [output.html.redirect] "/_doxygen/index.html" = "/cpp_refman.html" @@ -22,3 +23,9 @@ edit-url-template = "https://github.com/LDMX-Software/ldmx-software.github.io/ed "/Running-and-configuring-fire.html" = "/fire/intro.html" "/fire-config-tips.html" = "/fire/config-tips.html" "/Structure-of-Event-Processors.html" = "/fire/structure-of-event-processors.html" + +[preprocessor] + +[preprocessor.admonish] +command = "mdbook-admonish" +assets_version = "3.0.1" # do not edit: managed by `mdbook-admonish install` diff --git a/mdbook-admonish.css b/mdbook-admonish.css new file mode 100644 index 00000000..a0a566ab --- /dev/null +++ b/mdbook-admonish.css @@ -0,0 +1,345 @@ +@charset "UTF-8"; +:root { + --md-admonition-icon--admonish-note: url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--admonish-abstract: url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--admonish-info: url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--admonish-tip: url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--admonish-success: url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--admonish-question: url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--admonish-warning: url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--admonish-failure: url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--admonish-danger: url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--admonish-bug: url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--admonish-example: url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--admonish-quote: url("data:image/svg+xml;charset=utf-8,"); + --md-details-icon: url("data:image/svg+xml;charset=utf-8,"); +} + +:is(.admonition) { + display: flow-root; + margin: 1.5625em 0; + padding: 0 1.2rem; + color: var(--fg); + page-break-inside: avoid; + background-color: var(--bg); + border: 0 solid black; + border-inline-start-width: 0.4rem; + border-radius: 0.2rem; + box-shadow: 0 0.2rem 1rem rgba(0, 0, 0, 0.05), 0 0 0.1rem rgba(0, 0, 0, 0.1); +} +@media print { + :is(.admonition) { + box-shadow: none; + } +} +:is(.admonition) > * { + box-sizing: border-box; +} +:is(.admonition) :is(.admonition) { + margin-top: 1em; + margin-bottom: 1em; +} +:is(.admonition) > .tabbed-set:only-child { + margin-top: 0; +} +html :is(.admonition) > :last-child { + margin-bottom: 1.2rem; +} + +a.admonition-anchor-link { + display: none; + position: absolute; + left: -1.2rem; + padding-right: 1rem; +} +a.admonition-anchor-link:link, a.admonition-anchor-link:visited { + color: var(--fg); +} +a.admonition-anchor-link:link:hover, a.admonition-anchor-link:visited:hover { + text-decoration: none; +} +a.admonition-anchor-link::before { + content: "ยง"; +} + +:is(.admonition-title, summary.admonition-title) { + position: relative; + min-height: 4rem; + margin-block: 0; + margin-inline: -1.6rem -1.2rem; + padding-block: 0.8rem; + padding-inline: 4.4rem 1.2rem; + font-weight: 700; + background-color: rgba(68, 138, 255, 0.1); + print-color-adjust: exact; + -webkit-print-color-adjust: exact; + display: flex; +} +:is(.admonition-title, summary.admonition-title) p { + margin: 0; +} +html :is(.admonition-title, summary.admonition-title):last-child { + margin-bottom: 0; +} +:is(.admonition-title, summary.admonition-title)::before { + position: absolute; + top: 0.625em; + inset-inline-start: 1.6rem; + width: 2rem; + height: 2rem; + background-color: #448aff; + print-color-adjust: exact; + -webkit-print-color-adjust: exact; + mask-image: url('data:image/svg+xml;charset=utf-8,'); + -webkit-mask-image: url('data:image/svg+xml;charset=utf-8,'); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-size: contain; + content: ""; +} +:is(.admonition-title, summary.admonition-title):hover a.admonition-anchor-link { + display: initial; +} + +details.admonition > summary.admonition-title::after { + position: absolute; + top: 0.625em; + inset-inline-end: 1.6rem; + height: 2rem; + width: 2rem; + background-color: currentcolor; + mask-image: var(--md-details-icon); + -webkit-mask-image: var(--md-details-icon); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-size: contain; + content: ""; + transform: rotate(0deg); + transition: transform 0.25s; +} +details[open].admonition > summary.admonition-title::after { + transform: rotate(90deg); +} + +:is(.admonition):is(.admonish-note) { + border-color: #448aff; +} + +:is(.admonish-note) > :is(.admonition-title, summary.admonition-title) { + background-color: rgba(68, 138, 255, 0.1); +} +:is(.admonish-note) > :is(.admonition-title, summary.admonition-title)::before { + background-color: #448aff; + mask-image: var(--md-admonition-icon--admonish-note); + -webkit-mask-image: var(--md-admonition-icon--admonish-note); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.admonish-abstract, .admonish-summary, .admonish-tldr) { + border-color: #00b0ff; +} + +:is(.admonish-abstract, .admonish-summary, .admonish-tldr) > :is(.admonition-title, summary.admonition-title) { + background-color: rgba(0, 176, 255, 0.1); +} +:is(.admonish-abstract, .admonish-summary, .admonish-tldr) > :is(.admonition-title, summary.admonition-title)::before { + background-color: #00b0ff; + mask-image: var(--md-admonition-icon--admonish-abstract); + -webkit-mask-image: var(--md-admonition-icon--admonish-abstract); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.admonish-info, .admonish-todo) { + border-color: #00b8d4; +} + +:is(.admonish-info, .admonish-todo) > :is(.admonition-title, summary.admonition-title) { + background-color: rgba(0, 184, 212, 0.1); +} +:is(.admonish-info, .admonish-todo) > :is(.admonition-title, summary.admonition-title)::before { + background-color: #00b8d4; + mask-image: var(--md-admonition-icon--admonish-info); + -webkit-mask-image: var(--md-admonition-icon--admonish-info); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.admonish-tip, .admonish-hint, .admonish-important) { + border-color: #00bfa5; +} + +:is(.admonish-tip, .admonish-hint, .admonish-important) > :is(.admonition-title, summary.admonition-title) { + background-color: rgba(0, 191, 165, 0.1); +} +:is(.admonish-tip, .admonish-hint, .admonish-important) > :is(.admonition-title, summary.admonition-title)::before { + background-color: #00bfa5; + mask-image: var(--md-admonition-icon--admonish-tip); + -webkit-mask-image: var(--md-admonition-icon--admonish-tip); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.admonish-success, .admonish-check, .admonish-done) { + border-color: #00c853; +} + +:is(.admonish-success, .admonish-check, .admonish-done) > :is(.admonition-title, summary.admonition-title) { + background-color: rgba(0, 200, 83, 0.1); +} +:is(.admonish-success, .admonish-check, .admonish-done) > :is(.admonition-title, summary.admonition-title)::before { + background-color: #00c853; + mask-image: var(--md-admonition-icon--admonish-success); + -webkit-mask-image: var(--md-admonition-icon--admonish-success); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.admonish-question, .admonish-help, .admonish-faq) { + border-color: #64dd17; +} + +:is(.admonish-question, .admonish-help, .admonish-faq) > :is(.admonition-title, summary.admonition-title) { + background-color: rgba(100, 221, 23, 0.1); +} +:is(.admonish-question, .admonish-help, .admonish-faq) > :is(.admonition-title, summary.admonition-title)::before { + background-color: #64dd17; + mask-image: var(--md-admonition-icon--admonish-question); + -webkit-mask-image: var(--md-admonition-icon--admonish-question); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.admonish-warning, .admonish-caution, .admonish-attention) { + border-color: #ff9100; +} + +:is(.admonish-warning, .admonish-caution, .admonish-attention) > :is(.admonition-title, summary.admonition-title) { + background-color: rgba(255, 145, 0, 0.1); +} +:is(.admonish-warning, .admonish-caution, .admonish-attention) > :is(.admonition-title, summary.admonition-title)::before { + background-color: #ff9100; + mask-image: var(--md-admonition-icon--admonish-warning); + -webkit-mask-image: var(--md-admonition-icon--admonish-warning); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.admonish-failure, .admonish-fail, .admonish-missing) { + border-color: #ff5252; +} + +:is(.admonish-failure, .admonish-fail, .admonish-missing) > :is(.admonition-title, summary.admonition-title) { + background-color: rgba(255, 82, 82, 0.1); +} +:is(.admonish-failure, .admonish-fail, .admonish-missing) > :is(.admonition-title, summary.admonition-title)::before { + background-color: #ff5252; + mask-image: var(--md-admonition-icon--admonish-failure); + -webkit-mask-image: var(--md-admonition-icon--admonish-failure); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.admonish-danger, .admonish-error) { + border-color: #ff1744; +} + +:is(.admonish-danger, .admonish-error) > :is(.admonition-title, summary.admonition-title) { + background-color: rgba(255, 23, 68, 0.1); +} +:is(.admonish-danger, .admonish-error) > :is(.admonition-title, summary.admonition-title)::before { + background-color: #ff1744; + mask-image: var(--md-admonition-icon--admonish-danger); + -webkit-mask-image: var(--md-admonition-icon--admonish-danger); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.admonish-bug) { + border-color: #f50057; +} + +:is(.admonish-bug) > :is(.admonition-title, summary.admonition-title) { + background-color: rgba(245, 0, 87, 0.1); +} +:is(.admonish-bug) > :is(.admonition-title, summary.admonition-title)::before { + background-color: #f50057; + mask-image: var(--md-admonition-icon--admonish-bug); + -webkit-mask-image: var(--md-admonition-icon--admonish-bug); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.admonish-example) { + border-color: #7c4dff; +} + +:is(.admonish-example) > :is(.admonition-title, summary.admonition-title) { + background-color: rgba(124, 77, 255, 0.1); +} +:is(.admonish-example) > :is(.admonition-title, summary.admonition-title)::before { + background-color: #7c4dff; + mask-image: var(--md-admonition-icon--admonish-example); + -webkit-mask-image: var(--md-admonition-icon--admonish-example); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.admonish-quote, .admonish-cite) { + border-color: #9e9e9e; +} + +:is(.admonish-quote, .admonish-cite) > :is(.admonition-title, summary.admonition-title) { + background-color: rgba(158, 158, 158, 0.1); +} +:is(.admonish-quote, .admonish-cite) > :is(.admonition-title, summary.admonition-title)::before { + background-color: #9e9e9e; + mask-image: var(--md-admonition-icon--admonish-quote); + -webkit-mask-image: var(--md-admonition-icon--admonish-quote); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +.navy :is(.admonition) { + background-color: var(--sidebar-bg); +} + +.ayu :is(.admonition), +.coal :is(.admonition) { + background-color: var(--theme-hover); +} + +.rust :is(.admonition) { + background-color: var(--sidebar-bg); + color: var(--sidebar-fg); +} +.rust .admonition-anchor-link:link, .rust .admonition-anchor-link:visited { + color: var(--sidebar-fg); +} diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 4e582cf3..f9f01b12 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -4,6 +4,7 @@ - [Building and Installing ldmx-sw](Building-ldmx-sw.md) - [What the F.A.Q.?](faq.md) - [Generating Simulation Samples](Generating-Simulation-Samples.md) + - [Which SimParticles are saved?](which-sim-particles.md) - [Getting Started at SLAC](Getting-Started-with-ldmx-sw-at-SLAC.md) - [Running and Configuring fire](config/intro.md) - [Config File Basics](config/config-basics.md) diff --git a/src/simulation/resim.md b/src/simulation/resim.md index 8bacaff4..c053ad66 100644 --- a/src/simulation/resim.md +++ b/src/simulation/resim.md @@ -129,26 +129,11 @@ resim.actions.extend([ ### Storing all Simulated Particles The shower that happens in the calorimeters often creates many hundreds or even thousands of simulated particles. Thus we cannot save all of the simulated particles for all of our -events - otherwise we would run out of storage space on our computers! We get around this -issue by only saving a select group of particles during normal simulation which satisfy -one (or more) of the following. - -1. The simulated particle is one of the primary particles - - This is determined by the generators the user provides to the simulation. -2. The simulated particle is created in a region with `StoreTrajectories` set to `true` - - This is set within the GDML of the detector where we define regions. - In all of the current detectors, all of the regions will store trajectories _except_ - the calorimeters. -3. The simulated particle has its `SaveFlag` set to `true` - - This is determined by any extra `UserAction`s the simulation has attached to it. - -Currently, we do not have any `UserAction`s which set the `SaveFlag` to `false` because -`UserAction`s which are looking for particular simulated particles are usually trying -to get around the bulk "veto" imposed by the simulation throwing away simulated particles -that were created within the calorimeter region (either the ECal or the HCal). If your -simulation configuration has no `UserAction`s setting the `SaveFlag` to `false` (which -is highly likely), then we can insure that the simulation saves _all_ of the simulated -particles by setting `StoreTrajectories` to `true` _everywhere_. +events - otherwise we would run out of storage space on our computers! Checkout +[Which SimParticles are saved?](which-sim-particles.md) to learn more about how this choice +is made. For our purposes here, if your simulation configuration has no `UserAction`s setting +the `SaveFlag` to `false` (which is highly likely), then we can insure that the simulation +saves _all_ of the simulated particles by setting `StoreTrajectories` to `true` _everywhere_. First, make a local copy of the detector you are simulating so that you can reference it within the config script. diff --git a/src/which-sim-particles.md b/src/which-sim-particles.md new file mode 100644 index 00000000..db89577d --- /dev/null +++ b/src/which-sim-particles.md @@ -0,0 +1,106 @@ +# Which SimParticles are saved? + +Often, one of the first tasks users of ldmx-sw have is to inspect +the simulated particles that exist in an output file to learn about +what happened within an event. It is then fairly easy to find out that +not all of the simulated particles are actually saved into the output +file. One could find this out in multiple ways, but commonly, folks +find this out through one of two observations. + +1. The track IDs (the key in the `std::map` they are stored in) skip + numbers pretty regularly. +2. A SimParticle's "parent" or "daughter" is missing from the particles + saved for that event. + +In any case, this naturally leads to confusion; hence, this page trying +to explain it. + +```admonish warning title="Vocabulary Confusion" +I should emphasize here that we copy a `G4Track` into our `SimParticle`. +Geant4 has chosen to use the word "particle" to mean the definition of a +particle and its properties. Individual particles moving through space and +time are "tracks" in Geant4. We undo this switch-a-roo because we have +other things called "tracks". To further add confusion, parts of our geometry +infrastructure refer to "trajectories" which are also the same thing. +``` + +```admonish tip title="Data Structure" +First, it is helpful to be aware of the structure of the stored simulated +particle data. We save this data as a `std::map` +where the key of the map is the Geant4 track ID of the particle (a unique +integer within each event) and the value is a +[ldmx::SimParticle](https://ldmx-software.github.io/ldmx-sw/classldmx_1_1SimParticle.html) +that stores data about the particle. +``` + +## Motivation +Why not store all of the simulated particles? + +The answer to this question is pretty simple: it is a waste of space. +When a high energy electron hits a huge block of material, it undergoes +a process we call "showering" creating hundreds if not thousands of particles +as it interacts with the material. Most of these particles created during +a shower are not "interesting" for our purposes, so it is helpful to just +skip saving them. We do have the ability to store all of the particles in +an event if you desire, you can follow +[the same instructions](simulation/resim.md#storing-all-simulated-particles) +provided for storing all simulated particles during re-simulation. + +## Implementation +We get around this phenomena of showering by only saving a select group of +particles during normal simulation which satisfy one (or more) of the following. + +1. The simulated particle is one of the primary particles + - This is determined by the generators the user provides to the simulation. +2. The simulated particle is created in a region with `StoreTrajectories` set to `true` + - This is set within the GDML of the detector where we define regions. + In all of the current detectors, all of the regions will store trajectories _except_ + the calorimeters. +3. The simulated particle has its `SaveFlag` set to `true` + - This is determined by any extra `UserAction`s the simulation has attached to it. + +We do not usually have any `UserAction`s which set the `SaveFlag` to `false` because +`UserAction`s which are looking for particular simulated particles are usually trying +to get around the bulk "veto" imposed by the simulation throwing away simulated particles +that were created within the calorimeter region (either the ECal or the HCal). + +`UserAction`s that focus on looking for particular particles and making sure they are saved +already exist and can be used as examples. These actions (and their example configs) largely +live within the `Biasing` module of ldmx-sw. + +```admonish example title="Biasing/test/ecal_pn.py" +This config uses several user actions to make sure the a hard brem occurs within the target +and that high-energy photon undergoes a Photon-Nuclear (PN) interaction within the ECal. Since the PN interaction +is very interesting for us and it happens in the ECal, this config also uses the TrackProcessFilter +action which makes sure all particles that were created with the PN interaction are saved. + +With this config, the sim particles that exist in the output file fall into three categories. + +1. Starts outside of the ECal or HCal. This includes the primary electron that started the + simulation, but also may include other particles that are created as the electron journeys + from the beam into the calorimeters including the high energy photon created in the target. +2. Products of a PN Interaction. All particles that are created via the PN interaction are saved. + Since a PN interaction is required to happen in the ECal, many of these particles will have + daughter track IDs that do not exist in the particle map since they were not created via the + PN interaction and thus do not pass the filter. +``` + +```admonish example title="SimCore/test/basic.py" +This config (as the name implies) does not use any user actions and is just here to help +test the basic running of a simulation. + +With this config, the sim particles that exist are all created upstream of the calorimeters. +If you were to look at a distribution of all particles and their starting z location, you +would see none of them past ~200 mm where the front of the ECal and HCal are. These particles +include the primary electron fied by the generator and any particles it produces on its way +to the calorimeters. +``` + +```admonish note title="For Developers" +This particle saving infrastructure is handled by the +[simcore::UserTrackInformation](https://ldmx-software.github.io/ldmx-sw/classsimcore_1_1UserTrackInformation.html) +which stores the save flag referenced earlier and the +[simcore::g4user::TrackingAction](https://ldmx-software.github.io/ldmx-sw/classsimcore_1_1g4user_1_1TrackingAction.html) +which applies the defaults described above as well as passes the save decision onto +the class which creates the `SimParticle` for a `G4Track`. +```