1
0
Fork 0
mirror of https://github.com/gwm17/Mask.git synced 2024-11-22 10:18:50 -05:00

Merge pull request #1 from gwm17/devel

Devel
This commit is contained in:
Gordon McCann 2022-08-30 07:21:41 -07:00 committed by GitHub
commit d857ad9d4d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
98 changed files with 2756 additions and 4605 deletions

5
.gitignore vendored
View File

@ -9,14 +9,15 @@
*.pcm
*.o
*.a
*.so
*.swp
*.pickle
.DS_Store
Makefile
*.make
__pycache__
.vscode/
build/
lib/
bin/
###Keep this file###

View File

@ -1,5 +1,13 @@
cmake_minimum_required(VERSION 3.16)
if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
set(CMAKE_BUILD_TYPE "Release")
message("Building release")
else()
message("Building debug")
endif()
project(Mask)
set(MASK_BINARY_DIR ${CMAKE_CURRENT_SOURCE_DIR}/bin)
@ -8,8 +16,10 @@ set(MASK_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include)
set(CMAKE_CXX_STANDARD 17)
find_package(ROOT REQUIRED COMPONENTS GenVector)
add_subdirectory(src/vendor/catima)
add_subdirectory(src/Mask)
add_subdirectory(src/MaskApp)
add_subdirectory(src/Detectors)
add_subdirectory(src/Plotters/ROOT)
add_subdirectory(src/Plotters)

View File

@ -1,55 +1,55 @@
# MASK: Monte cArlo Simulation of Kinematics
MASK is a Monte Carlo simulation of reaction kinematics for use detector systems at Florida State University.
MASK is capable of simulating multi-step kinematic reaction-decay sequences, storing data in a lightweight binary format, after which the kinematic data can be fed to a detector geometry for efficiency testing. Currently geometries for ANASEN and SABRE are included in the code.
MASK is capable of simulating multi-step kinematic reaction-decay sequences, storing data in ROOT Trees, after which the kinematic data can be fed to a detector geometry for efficiency testing. Currently geometries for ANASEN and SABRE are included in the code.
## Building MASK
Dowload the repository from github. The code is to be built using Premake5, an open source and free project building software. To build on Linux and MacOSX run
`premake5 gmake2`
to generate the makefiles. Then execute
`make`
to build the program. To build on Windows run
`premake5 vs20xx`
where xx should be replaced with your version of Visual Studio, and then build as a normal Visual Studio project. For more documentation see the Premake wiki. By default `make` runs in Debug mode. For release mode use `make config=release`
Dowload the repository from github. CMake is use to build the project; in most environments you can build Mask using the following methods:
- `mkdir build`
- `cd build`
- `cmake ..`
- `make`
### Building RootPlot
One of the executables, RootPlot, requires linking against external libraries from the ROOT cern analysis package. Path to the necessary header files and libraries must be set by the user on a machine-by-machine basis in the premake5.lua file. Set the ROOTIncludepath and ROOTLibpath to match your install. An easy way to check for the paths on a unix system is through the root-config tool. root-config --cflags has the include path (the path after -I) and root-config --glibs has the lib path (after -L). If you do not have ROOT installed, you will not be able to compile RootPlot, and you will not be able to use the generic `make` command, which will try to build all executables. Instead use `make Mask` or `make DetectEff` (or `make config=release Mask`, etc).
Executables will be installed to the repostiory's `bin` directory. Libraries will be installed to the `lib` directory.
## Running MASK
By default Mask builds for release. To build for debug replace `cmake ..` with `cmake -DCMAKE_BUILD_TYPE=Debug ..`. Mask uses CMake to find the installed ROOT libraries and headers.
## Using the kinematics simulation
By default MASK is capable of simulating reactions of up to three steps. Here is a brief outline of each type:
0. A reaction of type 0 is a pure decay. It is assumed isotropic by default; any other case will require the modification of the code.
1. A reaction of type 1 is a pure reaction. It can incorporate all of the input file sampling parameters.
2. A reaction of type 2 is a reaction followed by a subsequent decay of the residual nucleus. Again, all sampling is allowed.
3. A reaction of type 3 is a reaction followed by a subsequent decay of the residual, followed by a decay of one of the products. Again, all sampling is allowed
0. A pure decay involves a "target" decaying into an ejectile and residual. It is assumed isotropic by default; any other case will require the modification of the code.
1. A single step reaction involves a target being hit by a projectile and emitting an ejectile and a residual. It can incorporate all of the input file sampling parameters.
2. A two step reaction is a single step reaction where the residual subsequently decays into two daughters (called breakups). Again, all sampling is allowed.
3. A three step reaction is a two step reaction where one of the breakup particles subsequently decays into two more breakup particles. Again, all sampling is allowed
For decays, a specific angular distribution can be given as input as a text file with values of coefficiencts of a Legendre polynomial series. Examples can be found in the `./etc` directory, including an isotropic case. It is assumed that the decays in the center-of-mass frame are isotropic in phi (i.e. m=0). Decay1 corresponds to the first decay, if there are multiple steps, Decay2 to the second. If there are no decays, these parameters are not used (or if only one decay, Decay2_AngularMomentum is not used). The input file requires that the user include target information, which will be used to calculate energy loss for all of the reactants and reaction products. The target can contain layers, and each layer can be composed of a compound of elements with a given stoichiometry. If the user wishes to not include energy loss in the kinematics, simply give all target layers a thickness of 0. Note that more layers and more thickness = more time spent calculating energy loss. These energy loss methods are only applicable for solid targets, and should not be applied to gas or liquid targets. Energy loss calculations have a stated uncertainty of approximately five percent.
For decays, a specific angular distribution can be given as input as a text file with values of coefficiencts of a Legendre polynomial series. Examples can be found in the `./etc` directory, including an isotropic case. It is assumed that the decays in the center-of-mass frame are isotropic in phi (i.e. m=0). Decay1 corresponds to the first decay, if there are multiple steps, Decay2 to the second. If there are no decays, these parameters are not used (or if only one decay, Decay2_AngularMomentum is not used). The input file requires that the user include target information, which will be used to calculate energy loss for all of the reactants and reaction products. The energy loss through materials is calculated using the `catima` library (found in `src/vendor`), which is a C/C++ interface to the `atima` library (the same energy loss methods used by LISE). The target can contain layers, and each layer can be composed of a compound of elements with a given stoichiometry. If the user wishes to not include energy loss in the kinematics, simply give all target layers a thickness of 0. Note that more layers and more thickness = more time spent calculating energy loss. These energy loss methods are only applicable for solid targets, and should not be applied to gas or liquid targets. Energy loss calculations have a stated uncertainty of approximately five percent.
To choose which detector scheme is run, modify the main function in DetectorEfficiency.cpp. The included geometries also have options to do an internal geometry consistency check and print out coordinates for drawing the detector arrays.
To run MASK simply do the following from the MASK repository:
To run MASK simply do the following from the MASK directory:
`./bin/Mask input.txt`
`./bin/MaskApp input.txt`
Input.txt can be replaced by any text file with the correct format.
## Using the detector geometry simulation
Detector geometry is encoded using ROOT math libraries in the `src/Detectors` folder. Two different detector geometries are already present: SPS-SABRE and ANASEN. To add a new geometry, follow the guidelines outlined by each of these cases.
To choose which detector scheme is run, modify the main function in `src/Detectors/main.cpp`. The included geometries also have options to do an internal geometry consistency check and print out coordinates for drawing the detector arrays, which can be useful for testing.
To run DetEff use the format
`./bin/DetEff <kinematics_datafile> <new_detection_datafile> <new_detection_statsfile>`
where the detection datafile contains all of the kinematics data as well as information about which particles are detected (this is in the mask file format) and the statsfile is a text file containing efficiency statistics.
where the detection datafile contains all of the kinematics data as well as information about which particles are detected and the statsfile is a text file containing efficiency statistics.
RootPlot is run as
## Data visualization
All data is saved as ROOT trees of std::vectors of Mask::Nucleus classes. To enable this, a ROOT dictionary is generated and linked into a shared library found in the `lib` directory of the repository. This allows the user to link to the shared library for accessing and analyzing the data generated by MASK.
Mask also provides a default visualization tool called RootPlot. RootPlot is run as
`./bin/RootPlot <datafile> <outputfile>`
where the datafile can be either the datafile from Mask or the datafile from DetEff. The outputfile is saved in the ROOT file format.
PyPlotter is run as
`./bin/PyPlotter <datafile> <outputfile>`
where again datafile can come from either Mask or DetEff. The outputfile is saved in the Python pickle file format. Pickled files can be reopened using the PyPlotViewer script run as
`./bin/PyPlotViewer <picklefile>`
## Requirements
MASK, the kinematics simulation, and DetEff, the detection efficiency simulation, require no external dependancies. The RootPlot plotting tool requires the ROOT cern data analysis package, and the PyPlotter tool requires Python3 and the matplotlib and numpy packages.
ROOT version 6.22 or greater is required
CMake version 3.0 or greater is required

5
bin/.gitignore vendored
View File

@ -1,5 +0,0 @@
###keep only the directory, not the contents###
*
!.gitignore
!PyPlotter
!PyPlotViewer

View File

@ -1,5 +0,0 @@
#!/bin/bash
FileName=$1;
./src/Plotters/Python/ViewPyPlots.py ${FileName}

View File

@ -1,6 +0,0 @@
#!/bin/bash
InputFile=$1;
OutputFile=$2;
./src/Plotters/Python/PyPlotter.py ${InputFile} ${OutputFile}

View File

@ -1,69 +0,0 @@
#ifndef ANASEN_EFFICIENCY_H
#define ANASEN_EFFICIENCY_H
#include <string>
#include "DetectorEfficiency.h"
#include "StripDetector.h"
#include "QQQDetector.h"
#include "Target.h"
#include "Nucleus.h"
#include "MaskFile.h"
#include "AnasenDeadChannelMap.h"
struct DetectorResult {
bool detectFlag = false;
Mask::Vec3 direction;
double energy_deposited = 0.0;
std::string det_name = "";
};
class AnasenEfficiency : public DetectorEfficiency {
public:
AnasenEfficiency();
~AnasenEfficiency();
void CalculateEfficiency(const std::string& inputname, const std::string& outputname, const std::string& statsname) override;
void DrawDetectorSystem(const std::string& filename) override;
double RunConsistencyCheck() override;
inline void SetDeadChannelMap(const std::string& filename) { dmap.LoadMapfile(filename); }
private:
DetectorResult IsRing1(Mask::Nucleus& nucleus);
DetectorResult IsRing2(Mask::Nucleus& nucleus);
DetectorResult IsQQQ(Mask::Nucleus& nucleus);
DetectorResult IsAnasen(Mask::Nucleus& nucleus);
void CountCoincidences(const Mask::MaskFileData& data, std::vector<int>& counts, Mask::RxnType rxn_type);
std::vector<StripDetector> m_Ring1, m_Ring2;
std::vector<QQQDetector> m_forwardQQQs;
std::vector<QQQDetector> m_backwardQQQs;
Mask::Target det_silicon;
AnasenDeadChannelMap dmap;
/**** ANASEN geometry constants *****/
const int n_sx3_per_ring = 12;
const int n_qqq = 4;
const double sx3_length = 0.075;
const double sx3_width = 0.04;
const double barrel_gap = 0.0254;
const double sx3_frame = 0.049; //0.049 is base gap due to frames
const double ring1_z = sx3_length/2.0 + sx3_frame + barrel_gap/2.0;
const double ring2_z = (-1.0)*(barrel_gap/2.0 + sx3_length/2.0);
const double qqq_nom_z = 0.0125 + sx3_length + sx3_frame + barrel_gap/2.0;
const double qqq_rinner = 0.0501;
const double qqq_router = 0.0990;
const double qqq_deltaphi = 1.52119;
const double qqq_z[4] = {qqq_nom_z, qqq_nom_z, qqq_nom_z, qqq_nom_z};
const double qqq_phi[4] = {5.49779, 0.785398, 2.35619, 3.92699};
const double ring_rho[12] = {0.0890601, 0.0889871, 0.0890354, 0.0890247, 0.0890354, 0.0890354, 0.0890247, 0.0890354, 0.0890354, 0.0890247, 0.0890354, 0.0890354};
const double ring_phi[12] = {4.97426, 5.49739, 6.02132, 0.261868, 0.785398, 1.30893, 1.83266, 2.35619, 2.87972, 3.40346, 3.92699, 4.45052};
/*************************/
static constexpr double threshold = 0.6; //MeV
static constexpr double deg2rad = M_PI/180.0;
static constexpr double si_thickness = 1000 * 1e-4 * 2.3926 * 1e6; //thickness in um -> eff thickness in ug/cm^2 for detector
};
#endif

View File

@ -1,34 +0,0 @@
#ifndef ANGULARDISTRIBUTION_H
#define ANGULARDISTRIBUTION_H
#include <string>
#include <vector>
#include <random>
namespace Mask {
class AngularDistribution {
public:
AngularDistribution();
AngularDistribution(const std::string& file);
~AngularDistribution();
void ReadDistributionFile(const std::string& file);
double GetRandomCosTheta();
inline int GetL() { return L; }
inline double GetBranchingRatio() { return branchingRatio; }
private:
inline bool IsIsotropic() { return isoFlag; }
std::uniform_real_distribution<double> uniform_cosine_dist;
std::uniform_real_distribution<double> uniform_prob_dist;
double branchingRatio;
int L;
std::vector<double> constants;
bool isoFlag;
};
}
#endif

View File

@ -1,41 +0,0 @@
#ifndef DECAYSYSTEM_H
#define DECAYSYSTEM_H
#include "ReactionSystem.h"
#include "AngularDistribution.h"
namespace Mask {
class DecaySystem: public ReactionSystem {
public:
DecaySystem();
DecaySystem(std::vector<int>& z, std::vector<int>& a);
~DecaySystem();
bool SetNuclei(std::vector<int>& z, std::vector<int>& a) override;
void RunSystem() override;
const std::vector<Nucleus>& GetNuclei() override;
inline void SetDecay1Distribution(const std::string& filename) { decay1dist.ReadDistributionFile(filename); }
inline const Nucleus& GetTarget() const { return step1.GetTarget(); }
inline const Nucleus& GetEjectile() const { return step1.GetEjectile(); }
inline const Nucleus& GetResidual() const { return step1.GetResidual(); }
inline int GetDecay1AngularMomentum() { return decay1dist.GetL(); }
inline double GetDecay1BranchingRatio() { return decay1dist.GetBranchingRatio(); }
private:
void LinkTarget() override;
void SetSystemEquation() override;
Reaction step1;
AngularDistribution decay1dist;
};
}
#endif

View File

@ -1,133 +0,0 @@
#ifndef ELOSS_TABLES_H
#define ELOSS_TABLES_H
namespace Mask {
#define MAX_Z 93 //Maximum number of elements for which we have hydrogen coefficients
/*Atomic Masses for elements H through U. Taken from ELAST data*/
static double NATURAL_MASS[MAX_Z] =
{0,
1.00797, 4.0026, 6.939, 9.0122, 10.818,
12.01115, 14.0067, 15.9994, 18.99984, 20.183,
22.9898, 24.312, 26.9815, 28.086, 30.9738,
32.064, 35.453, 39.948, 39.102, 40.08,
44.956, 47.90, 50.942, 51.996, 54.938,
55.847, 58.933, 58.71, 63.54, 65.37,
69.72, 72.59, 74.922, 78.96, 79.909,
83.80, 85.47, 87.62, 88.909, 91.22,
92.906, 95.94, 98., 101.07, 102.905,
106.4, 107.87, 112.4, 114.82, 118.69,
121.75, 127.60, 126.904, 131.3, 132.905,
137.34, 138.91, 140.12, 140.907, 144.24,
146., 150.35, 151.96, 157.25, 158.924,
162.50, 164.93, 167.26, 168.934, 173.04,
174.97, 178.49, 180.948, 183.85, 186.2,
190.2, 192.2, 195.09, 196.967, 200.59,
204.37, 207.19, 208.98, 209., 210.,
222., 223., 226., 227., 232.038,
231., 238.03 };
/*Stopping power coefficients for hydrogen into Z
*Taken from Ziegler, Hydrogen Stopping Powers and Ranges in All Elements, Volume 3 of
*The Stopping and Ranges of Ions in Matter, 1977, Pergamon Press Inc.
*Expanded table for method given in O.G. Spanc
*Note: some elements represent extrapolations when there was no data to fit
*/
static double HYDROGEN_COEFF[MAX_Z][12] = {
/*Blank*/{0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.},
/*H*/{1.262,1.44,242.6,1.2E4,0.1159,0.0005099,5.436E4,-5.052,2.049,-0.3044,0.01966,-0.0004659},
/*He*/{1.229,1.397,484.5,5873,0.05225,0.00102,2.451E4,-2.158,0.8278,-0.1172,0.007259,-0.000166},
/*Li*/{1.411,1.6,725.6,3013,0.04578,0.00153,2.147E4,-0.5831,0.562,-0.1183,0.009298,-0.0002498},
/*Be*/{2.248,2.59,966,153.8,0.03475,0.002039,1.63E4,0.2779,0.1745,-0.05684,0.005155,-0.0001488},
/*B*/{2.474,2.815,1206,1060,0.02855,0.002549,1.345E4,-2.445,1.283,-0.2205,0.0156,-0.000393},
/*C*/{2.631,2.989,1445,957.2,0.02819,0.003059,1.322E4,-4.38,2.044,-0.3283,0.02221,-0.0005417},
/*N*/{2.954,3.35,1683,1900,0.02513,0.003569,1.179E4,-5.054,2.325,-0.3713,0.02506,-0.0006109},
/*O*/{2.652,3,1920,2000,0.0223,0.004079,1.046E4,-6.734,3.019,-0.4748,0.03171,-0.0007669},
/*F*/{2.085,2.352,2157,2634,0.01816,0.004589,8517,-5.571,2.449,-0.3781,0.02483,-0.0005919},
/*Ne*/{1.951,2.199,2393,2699,0.01568,0.005099,7353,-4.408,1.879,-0.2814,0.01796,-0.0004168},
/*Na*/{2.542,2.869,2628,1854,0.01472,0.005609,6905,-4.959,2.073,-0.3054,0.01921,-0.0004403},
/*Mg*/{3.792,4.293,2862,1009,0.01397,0.006118,6551,-5.51,2.266,-0.3295,0.02047,-0.0004637},
/*Al*/{4.154,4.739,2766,164.5,0.02023,0.006628,6309,-6.061,2.46,-0.3535,0.02173,-0.0004871},
/*Si*/{4.15,4.7,3329,550,0.01321,0.007138,6194,-6.294,2.538,-0.3628,0.0222,-0.0004956},
/*P*/{3.232,3.647,3561,1560,0.01267,0.007648,5942,-6.527,2.616,-0.3721,0.02267,-0.000504},
/*S*/{3.447,3.891,3792,1219,0.01211,0.008158,5678,-6.761,2.694,-0.3814,0.02314,-0.0005125},
/*Cl*/{5.047,5.714,4023,878.6,0.01178,0.008668,5524,-6.994,2.773,-0.3907,0.02361,-0.0005209},
/*Ar*/{5.731,6.5,4253,530,0.01123,0.009178,5268,-7.227,2.851,-0.4,0.02407,-0.0005294},
/*K*/{5.151,5.833,4482,545.7,0.01129,0.009687,5295,-7.44,2.923,-0.4094,0.02462,-0.0005411},
/*Ca*/{5.521,6.252,4710,553.3,0.01112,0.0102,5214,-7.653,2.995,-0.4187,0.02516,-0.0005529},
/*Sc*/{5.201,5.884,4938,560.9,0.009995,0.01071,4688,-8.012,3.123,-0.435,0.02605,-0.0005707},
/*Ti*/{4.862,5.496,5165,568.5,0.009474,0.01122,4443,-8.371,3.251,-0.4513,0.02694,-0.0005886},
/*V*/{4.48,5.055,5391,952.3,0.009117,0.01173,4276,-8.731,3.379,-0.4676,0.02783,-0.0006064},
/*Cr*/{3.983,4.489,5616,1336,0.008413,0.01224,3946,-9.09,3.507,-0.4838,0.02872,-0.0006243},
/*Mn*/{3.469,3.907,5725,1461,0.008829,0.01275,3785,-9.449,3.635,-0.5001,0.02961,-0.0006421},
/*Fe*/{3.519,3.963,6065,1243,0.007782,0.01326,3650,-9.809,3.763,-0.5164,0.0305,-0.00066},
/*Co*/{3.14,3.535,6288,1372,0.007361,0.01377,3453,-10.17,3.891,-0.5327,0.03139,-0.0006779},
/*Ni*/{3.553,4.004,6205,555.1,0.008763,0.01428,3297,-10.53,4.019,-0.549,0.03229,-0.0006957},
/*Cu*/{3.696,4.175,4673,387.8,0.02188,0.01479,3174,-11.18,4.252,-0.5791,0.03399,-0.0007314},
/*Zn*/{4.21,4.75,6953,295.2,0.006809,0.0153,3194,-11.57,4.394,-0.598,0.03506,-0.0007537},
/*Ga*/{5.041,5.697,7173,202.6,0.006725,0.01581,3154,-11.95,4.537,-0.6169,0.03613,-0.0007759},
/*Ge*/{5.554,6.3,6496,110,0.009689,0.01632,3097,-12.34,4.68,-0.6358,0.03721,-0.0007981},
/*As*/{5.323,6.012,7611,292.5,0.006447,0.01683,3024,-12.72,4.823,-0.6547,0.03828,-0.0008203},
/*Se*/{5.874,6.656,7395,117.5,0.007684,0.01734,3006,-13.11,4.965,-0.6735,0.03935,-0.0008425},
/*Br*/{5.611,6.335,8046,365.2,0.006244,0.01785,2928,-13.4,5.083,-0.6906,0.04042,-0.0008675},
/*Kr*/{6.411,7.25,8262,220,0.006087,0.01836,2855,-13.69,5.2,-0.7076,0.0415,-0.0008925},
/*Rb*/{5.694,6.429,8478,292.9,0.006087,0.01886,2855,-13.92,5.266,-0.714,0.04173,-0.0008943},
/*Sr*/{6.339,7.159,8693,330.3,0.006003,0.01937,2815,-14.14,5.331,-0.7205,0.04196,-0.0008962},
/*Y*/{6.407,7.234,8907,367.8,0.005889,0.01988,2762,-14.36,5.397,-0.7269,0.04219,-0.000898},
/*Zr*/{6.734,7.603,9120,405.2,0.005765,0.02039,2704,-14.59,5.463,-0.7333,0.04242,-0.0008998},
/*Nb*/{6.902,7.791,9333,442.7,0.005587,0.0209,2621,-16.22,6.094,-0.8225,0.04791,-0.001024},
/*Mo*/{6.425,7.248,9545,480.2,0.005367,0.02141,2517,-17.85,6.725,-0.9116,0.05339,-0.001148},
/*Tc*/{6.799,7.671,9756,517.6,0.005315,0.02192,2493,-17.96,6.752,-0.9135,0.05341,-0.001147},
/*Ru*/{6.108,6.887,9966,555.1,0.005151,0.02243,2416,-18.07,6.779,-0.9154,0.05342,-0.001145},
/*Rh*/{5.924,6.677,1.018E4,592.5,0.004919,0.02294,2307,-18.18,6.806,-0.9173,0.05343,-0.001143},
/*Pd*/{5.238,5.9,1.038E4,630,0.004758,0.02345,2231,-18.28,6.833,-0.9192,0.05345,-0.001142},
/*Ag*/{5.623,6.354,7160,337.6,0.01394,0.02396,2193,-18.39,6.86,-0.9211,0.05346,-0.00114},
/*Cd*/{5.814,6.554,1.08E4,355.5,0.004626,0.02447,2170,-18.62,6.915,-0.9243,0.0534,-0.001134},
/*In*/{6.23,7.024,1.101E4,370.9,0.00454,0.02498,2129,-18.85,6.969,-0.9275,0.05335,-0.001127},
/*Sn*/{6.41,7.227,1.121E4,386.4,0.004474,0.02549,2099,-19.07,7.024,-0.9308,0.05329,-0.001121},
/*Sb*/{7.5,8.48,8608,348,0.009074,0.026,2069,-19.57,7.225,-0.9603,0.05518,-0.001165},
/*Te*/{6.979,7.871,1.162E4,392.4,0.004402,0.02651,2065,-20.07,7.426,-0.9899,0.05707,-0.001209},
/*I*/{7.725,8.716,1.183E4,394.8,0.004376,0.02702,2052,-20.56,7.627,-1.019,0.05896,-0.001254},
/*Xe*/{8.231,9.289,1.203E4,397.3,0.004384,0.02753,2056,-21.06,7.828,-1.049,0.06085,-0.001298},
/*Cs*/{7.287,8.218,1.223E4,399.7,0.004447,0.02804,2086,-20.4,7.54,-1.004,0.05782,-0.001224},
/*Ba*/{7.899,8.911,1.243E4,402.1,0.004511,0.02855,2116,-19.74,7.252,-0.9588,0.05479,-0.001151},
/*La*/{8.041,9.071,1.263E4,404.5,0.00454,0.02906,2129,-19.08,6.964,-0.9136,0.05176,-0.001077},
/*Ce*/{7.489,8.444,1.283E4,406.9,0.00442,0.02957,2073,-18.43,6.677,-0.8684,0.04872,-0.001003},
/*Pr*/{7.291,8.219,1.303E4,409.3,0.004298,0.03008,2016,-17.77,6.389,-0.8233,0.04569,-0.0009292},
/*Nd*/{7.098,8,1.323E4,411.8,0.004182,0.03059,1962,-17.11,6.101,-0.7781,0.04266,-0.0008553},
/*Pm*/{6.91,7.786,1.343E4,414.2,0.00405,0.0311,1903,-16.45,5.813,-0.733,0.03963,-0.0007815},
/*Sm*/{6.728,7.58,1.362E4,416.6,0.003976,0.03161,1865,-15.79,5.526,-0.6878,0.0366,-0.0007077},
/*Eu*/{6.551,7.38,1.382E4,419,0.003877,0.03212,1819,-15.13,5.238,-0.6426,0.03357,-0.0006339},
/*Gd*/{6.739,7.592,1.402E4,421.4,0.003863,0.03263,1812,-14.47,4.95,-0.5975,0.03053,-0.0005601},
/*Tb*/{6.212,6.996,1.421E4,423.9,0.003725,0.03314,1747,-14.56,4.984,-0.6022,0.03082,-0.0005668},
/*Dy*/{5.517,6.21,1.44E4,426.3,0.003632,0.03365,1703,-14.65,5.018,-0.6069,0.03111,-0.0005734},
/*Ho*/{5.219,5.874,1.46E4,428.7,0.003498,0.03416,1640,-14.74,5.051,-0.6117,0.03141,-0.0005801},
/*Er*/{5.071,5.706,1.479E4,433,0.003405,0.03467,1597,-14.83,5.085,-0.6164,0.0317,-0.0005867},
/*Tm*/{4.926,5.542,1.498E4,433.5,0.003342,0.03518,1567,-14.91,5.119,-0.6211,0.03199,-0.0005933},
/*Yb*/{4.787, 5.386,1.517E4,435.9,0.003292,0.03569,1544,-15,5.153,-0.6258,0.03228,-0.0006},
/*Lu*/{4.893, 5.505,1.536E4,438.4,0.003243,0.0362,1521,-15.09,5.186,-0.6305,0.03257,-0.0006066},
/*Hf*/{5.028, 5.657,1.555E4,440.8,0.003195,0.03671,1499,-15.18,5.22,-0.6353,0.03286,-0.0006133},
/*Ta*/{4.738, 5.329,1.574E4,443.2,0.003186,0.03722,1494,-15.27,5.254,-0.64,0.03315,-0.0006199},
/*W*/{4.574, 5.144,1.593E4,442.4,0.003144,0.03773,1475,-15.67,5.392,-0.6577,0.03418,-0.0006426},
/*Re*/{5.2, 5.851,1.612E4,441.6,0.003122,0.03824,1464,-16.07,5.529,-0.6755,0.03521,-0.0006654},
/*Os*/{5.07, 5.704,1.63E4,440.9,0.003082,0.03875,1446,-16.47,5.667,-0.6932,0.03624,-0.0006881},
/*Ir*/{4.945, 5.563,1.649E4,440.1,0.002965,0.03926,1390,-16.88,5.804,-0.711,0.03727,-0.0007109},
/*Pt*/{4.476, 5.034,1.667E4,439.3,0.002871,0.03977,1347,-17.28,5.942,-0.7287,0.0383,-0.0007336},
/*Au*/{4.856, 5.46,1.832E4,438.5,0.002542,0.04028,1354,-17.02,5.846,-0.7149,0.0374,-0.0007114},
/*Hg*/{4.308, 4.843,1.704E4,487.8,0.002882,0.04079,1352,-17.84,6.183,-0.7659,0.04076,-0.0007925},
/*Tl*/{4.723, 5.311,1.722E4,537,0.002913,0.0413,1366,-18.66,6.52,-0.8169,0.04411,-0.0008737},
/*Pb*/{5.319, 5.982,1.74E4,586.3,0.002871,0.04181,1347,-19.48,6.857,-0.8678,0.04747,-0.0009548},
/*Bi*/{5.956, 6.7,1.78E4,677,0.00266,0.04232,1336,-19.55,6.871,-0.8686,0.04748,-0.0009544},
/*Po*/{6.158, 6.928,1.777E4,586.3,0.002812,0.04283,1319,-19.62,6.884,-0.8694,0.04748,-0.000954},
/*At*/{6.204, 6.979,1.795E4,586.3,0.002776,0.04334,1302,-19.69,6.898,-0.8702,0.04749,-0.0009536},
/*Rn*/{6.181, 6.954,1.812E4,586.3,0.002748,0.04385,1289,-19.76,6.912,-0.871,0.04749,-0.0009532},
/*Fr*/{6.949, 7.82,1.83E4,586.3,0.002737,0.04436,1284,-19.83,6.926,-0.8718,0.0475,-0.0009528},
/*Ra*/{7.506, 8.448,1.848E4,586.3,0.002727,0.04487,1279,-19.9,6.94,-0.8726,0.04751,-0.0009524},
/*Ac*/{7.649, 8.609,1.866E4,586.3,0.002697,0.04538,1265,-19.97,6.953,-0.8733,0.04751,-0.000952},
/*Th*/{7.71, 8.679,1.883E4,586.3,0.002641,0.04589,1239,-20.04,6.967,-0.8741,0.04752,-0.0009516},
/*Pa*/{7.407, 8.336,1.901E4,586.3,0.002603,0.0464,1221,-20.11,6.981,-0.8749,0.04752,-0.0009512},
/*U*/{7.29, 8.204,1.918E4,586.3,0.002573,0.04691,1207,-20.18,6.995,-0.8757,0.04753,-0.0009508}
};
}
#endif

View File

@ -1,58 +0,0 @@
/*
EnergyLoss.h
Code for calculating the energy loss of a charged, massive particle through an arbitrary medium.
Based on code written by D.W. Visser at Yale for the original SPANC. Uses energy loss calulations
described by Ziegler in various SRIM textbooks.
Written by G.W. McCann Aug. 2020
*/
#ifndef ENERGYLOSS_H
#define ENERGYLOSS_H
#include <iostream>
#include <string>
#include <vector>
#include <fstream>
#include <cmath>
#include "MassLookup.h"
namespace Mask {
class EnergyLoss {
public:
EnergyLoss();
~EnergyLoss();
double GetEnergyLoss(int zp, int ap, double e_initial, double thickness);
double GetReverseEnergyLoss(int zp, int ap, double e_final, double thickness);
double GetRange(double energy);
void SetTargetComponents(const std::vector<int>& Zt, const std::vector<int>& At, const std::vector<int>& Stoich);
private:
double GetElectronicStoppingPower(double energy);
double GetNuclearStoppingPower(double energy);
double GetTotalStoppingPower(double energy);
double Hydrogen_dEdx_Low(double e_per_u, int z);
double Hydrogen_dEdx_Med(double e_per_u, int z);
double Hydrogen_dEdx_High(double e_per_u, double energy, int z);
double CalculateEffectiveChargeRatio(double e_per_u, int z);
int ZP, AP;
double MP; //units of u, isotopic
double comp_denom;
std::vector<int> ZT, AT;
std::vector<double> targ_composition;
//constants for calculations
static constexpr double MAX_FRACTIONAL_STEP = 0.001;
static constexpr double MAX_DEPTH = 50;
static constexpr double MAX_H_E_PER_U = 100000.0;
static constexpr double AVOGADRO = 0.60221367; //N_A times 10^(-24) for converting
static constexpr double MEV2U = 1.0/931.4940954;
static constexpr double H_RESTMASS = 938.27231; //MeV, for beta calc
};
}
#endif

View File

@ -1,38 +0,0 @@
#ifndef MASKAPP_H
#define MASKAPP_H
#include "ReactionSystem.h"
#include "DecaySystem.h"
#include "OneStepSystem.h"
#include "TwoStepSystem.h"
#include "ThreeStepSystem.h"
#include "RxnType.h"
namespace Mask {
class MaskApp {
public:
MaskApp();
~MaskApp();
bool LoadConfig(const std::string& filename);
bool SaveConfig(const std::string& filename);
inline int GetNumberOfSamples() const { return m_nsamples; };
inline const std::string GetSystemName() const { return m_sys == nullptr ? "" : m_sys->GetSystemEquation(); };
inline const std::string GetOutputName() const { return m_outfile_name; };
inline const RxnType GetReactionType() const { return m_rxn_type; };
void Run();
private:
ReactionSystem* m_sys;
std::string m_outfile_name;
RxnType m_rxn_type;
int m_nsamples;
};
}
#endif

View File

@ -1,77 +0,0 @@
#ifndef MASKFILE_H
#define MASKFILE_H
#include <string>
#include <fstream>
#include <vector>
#include "Nucleus.h"
#include "RxnType.h"
namespace Mask {
struct MaskFileHeader {
RxnType rxn_type = RxnType::None;
int nsamples = -1;
};
struct MaskFileData {
std::vector<double> E, KE, p, theta, phi; //ordered: target, (if not decay)projectile, ejectile, residual, break1...
std::vector<int> Z, A;
std::vector<bool> detect_flag;
bool eof = false; //flag on end of file
};
class MaskFile {
public:
enum class FileType {
read,
write,
append,
none
};
MaskFile();
MaskFile(const std::string& name, MaskFile::FileType type);
bool Open(const std::string& name, MaskFile::FileType type);
inline bool IsOpen() { return file.is_open(); }
void Close();
void WriteHeader(RxnType rxn_type, int nsamples);
void WriteData(const std::vector<Nucleus>& data);
void WriteData(const MaskFileData& data);
MaskFileHeader ReadHeader();
MaskFileData ReadData();
private:
FileType file_type;
std::string filename;
uint64_t buffer_position;
uint64_t buffer_end;
uint32_t data_size;
RxnType m_rxn_type;
uint32_t buffersize_bytes;
std::fstream file;
std::vector<char> data_buffer;
static constexpr uint32_t onestep_rxn_n = 2;
static constexpr uint32_t twostep_rxn_n = 4;
static constexpr uint32_t threestep_rxn_n = 6;
static constexpr uint64_t buffersize = 10000; //number of events
static constexpr int width = 0;
static constexpr int precision = 3;
static constexpr std::size_t double_size = sizeof(double);
static constexpr std::size_t int_size = sizeof(uint32_t);
static constexpr std::size_t bool_size = sizeof(bool);
};
};
#endif

View File

@ -1,64 +0,0 @@
/*
Nucleus.h
Nucleus is a derived class of Vec4. A nucleus is the kinematics is essentially a 4 vector with the
additional properties of the number of total nucleons (A), the number of protons (Z), a ground state mass,
an exctitation energy, and an isotopic symbol.
--GWM Jan 2021
*/
#ifndef NUCLEUS_H
#define NUCLEUS_H
#include "Vec4.h"
#include <string>
namespace Mask {
class Nucleus : public Vec4 {
public:
Nucleus();
Nucleus(int Z, int A);
Nucleus(int Z, int A, double px, double py, double pz, double E);
virtual ~Nucleus() override;
bool SetIsotope(int Z, int A);
inline void SetThetaCM(double tcm) { m_theta_cm = tcm; }; //save theta in rxn CM frame
inline int GetZ() const { return m_z; };
inline int GetA() const { return m_a; };
inline double GetExcitationEnergy() const { return GetInvMass() - m_gs_mass; };
inline double GetGroundStateMass() const { return m_gs_mass; };
inline const char* GetIsotopicSymbol() const { return m_symbol.c_str(); };
inline double GetThetaCM() const { return m_theta_cm; };
inline void SetDetected() { m_detectFlag = true; };
inline void SetNotDetected() { m_detectFlag = false; };
inline bool IsDetected() const { return m_detectFlag; };
inline Nucleus& operator=(const Nucleus& rhs) {
SetIsotope(rhs.GetZ(), rhs.GetA());
SetVectorCartesian(rhs.GetPx(), rhs.GetPy(), rhs.GetPz(), rhs.GetE());
SetThetaCM(rhs.GetThetaCM());
return *this;
};
//Conservation of nucleons and momentum
inline Nucleus operator+(const Nucleus& daughter) {
return Nucleus(GetZ()+daughter.GetZ(), GetA()+daughter.GetA(), GetPx()+daughter.GetPx(), GetPy()+daughter.GetPy(), GetPz()+daughter.GetPz(), GetE()+daughter.GetE());
};
inline Nucleus operator-(const Nucleus& daughter) {
return (GetZ() - daughter.GetZ()) <= 0 || (GetA() - daughter.GetA()) <= 0 ? Nucleus() :
Nucleus(GetZ()-daughter.GetZ(), GetA() - daughter.GetA(), GetPx()-daughter.GetPx(), GetPy()-daughter.GetPy(), GetPz()-daughter.GetPz(), GetE()-daughter.GetE());
};
private:
int m_z, m_a;
double m_gs_mass;
double m_theta_cm;
std::string m_symbol;
bool m_detectFlag;
};
};
#endif

View File

@ -1,34 +0,0 @@
#ifndef ONESTEPSYSTEM_H
#define ONESTEPSYSTEM_H
#include "ReactionSystem.h"
namespace Mask {
class OneStepSystem: public ReactionSystem {
public:
OneStepSystem();
OneStepSystem(std::vector<int>& z, std::vector<int>& a);
~OneStepSystem();
bool SetNuclei(std::vector<int>& z, std::vector<int>& a) override;
void RunSystem() override;
const std::vector<Nucleus>& GetNuclei() override;
inline void SetReactionThetaType(int type) { step1.SetEjectileThetaType(type); };
inline const Nucleus& GetTarget() const { return step1.GetTarget(); };
inline const Nucleus& GetProjectile() const { return step1.GetProjectile(); };
inline const Nucleus& GetEjectile() const { return step1.GetEjectile(); };
inline const Nucleus& GetResidual() const { return step1.GetResidual(); };
private:
void LinkTarget() override;
void SetSystemEquation() override;
Reaction step1;
};
}
#endif

View File

@ -1,57 +0,0 @@
/*
QQQDetector.h
Class implementing geometry for QQQDetector where the detector is perpendicular to the beam axis.
Detector is first generated centered on the x-axis (phi=0)
Coordinate convention : +z is downstream, -z is upstream. +y is vertically down in the lab.
*/
#ifndef QQQDETECTOR_H
#define QQQDETECTOR_H
#include <cmath>
#include <vector>
#include <random>
#include "Vec3.h"
#include "Rotation.h"
#include "RandomGenerator.h"
class QQQDetector {
public:
QQQDetector(double R_in, double R_out, double deltaPhi, double phiCentral, double z, double x=0, double y=0);
~QQQDetector();
inline Mask::Vec3 GetRingCoordinates(int ringch, int corner) { return m_ringCoords[ringch][corner]; }
inline Mask::Vec3 GetWedgeCoordinates(int wedgech, int corner) { return m_wedgeCoords[wedgech][corner]; }
inline Mask::Vec3 GetNorm() { return m_norm; }
Mask::Vec3 GetTrajectoryCoordinates(double theta, double phi);
std::pair<int, int> GetTrajectoryRingWedge(double theta, double phi);
Mask::Vec3 GetHitCoordinates(int ringch, int wedgech);
inline void TurnOnRandomizedCoordinates() { rndmFlag = true; }
inline void TurnOffRandomizedCoordinates() { rndmFlag = false; }
inline int GetNumberOfRings() { return nrings; }
inline int GetNumberOfWedges() { return nwedges; }
private:
inline bool CheckChannel(int ch) { return (ch >=0 && ch < nrings); }
inline bool CheckCorner(int corner) { return (corner >=0 && corner < 4); }
void CalculateCorners();
Mask::Vec3 TransformCoordinates(Mask::Vec3& vector) { return m_ZRot*vector + m_translation; }
double m_Rinner, m_Router, m_deltaR, m_deltaPhi, m_deltaPhi_per_wedge, m_phiCentral;
std::vector<std::vector<Mask::Vec3>> m_ringCoords, m_wedgeCoords;
Mask::Vec3 m_translation;
Mask::Vec3 m_norm;
Mask::ZRotation m_ZRot;
std::uniform_real_distribution<double> m_uniform_fraction;
bool rndmFlag;
static constexpr int nrings = 16;
static constexpr int nwedges = 16;
static constexpr double deg2rad = M_PI/180.0;
};
#endif

View File

@ -1,25 +0,0 @@
#ifndef RANDOMGENERATOR_H
#define RANDOMGENERATOR_H
#include <random>
namespace Mask {
class RandomGenerator {
public:
~RandomGenerator();
inline std::mt19937& GetGenerator() { return rng; }
inline static RandomGenerator& GetInstance() {
static RandomGenerator s_instance;
return s_instance;
}
private:
RandomGenerator();
std::mt19937 rng;
};
}
#endif

View File

@ -1,78 +0,0 @@
/*
Reaction.h
Reaction is a class which implements either a decay or scattering reaction. As such it requires either
3 (decay) or 4 (scattering) nuclei to perform any calcualtions. I also links together the target, which provides
energy loss calculations, with the kinematics. Note that Reaction does not own the LayeredTarget.
--GWM Jan. 2021
*/
#ifndef REACTION_H
#define REACTION_H
#include "Nucleus.h"
#include "LayeredTarget.h"
namespace Mask {
class Reaction {
public:
Reaction();
Reaction(int zt, int at, int zp, int ap, int ze, int ae);
~Reaction();
bool Calculate();
void SetNuclei(int zt, int at, int zp, int ap, int ze, int ae);
void SetNuclei(const Nucleus* nucs);
void SetBeamKE(double bke);
void SetEjectileThetaType(int type);
inline void SetLayeredTarget(LayeredTarget* targ) { target = targ; };
inline void SetPolarRxnAngle(double theta) { m_theta = theta; };
inline void SetAzimRxnAngle(double phi) { m_phi = phi; };
inline void SetExcitation(double ex) { m_ex = ex; };
inline void SetTarget(const Nucleus& nuc) { reactants[0] = nuc; };
inline void SetTarget(int z, int a) { reactants[0] = Nucleus(z, a); };
inline void SetProjectile(const Nucleus& nuc) { reactants[1] = nuc; };
inline void SetProjectile(int z, int a) { reactants[1] = Nucleus(z, a); };
inline void SetEjectile(const Nucleus& nuc) { reactants[2] = nuc; };
inline void SetEjectile(int z, int a) { reactants[2] = Nucleus(z, a); };
inline void SetResidual(const Nucleus& nuc) { reactants[3] = nuc; };
inline void SetResidual(int z, int a) { reactants[3] = Nucleus(z, a); };
inline void SetRxnLayer(int layer) { rxnLayer = layer; };
inline void TurnOffResidualEloss() { resid_elossFlag = false; };
inline void TurnOnResidualEloss() { resid_elossFlag = true; };
inline bool IsDecay() { return decayFlag; };
inline const Nucleus* GetNuclei() const { return &(reactants[0]); };
inline const Nucleus& GetProjectile() const { return reactants[1]; };
inline const Nucleus& GetTarget() const { return reactants[0]; };
inline const Nucleus& GetEjectile() const { return reactants[2]; };
inline const Nucleus& GetResidual() const { return reactants[3]; };
inline int GetRxnLayer() { return rxnLayer; };
inline void ResetTarget() { reactants[0].SetVectorCartesian(0,0,0, reactants[0].GetGroundStateMass()); }
inline void ResetProjectile() { reactants[1].SetVectorCartesian(0,0,0, reactants[1].GetGroundStateMass()); }
inline void ResetEjectile() { reactants[2].SetVectorCartesian(0,0,0, reactants[2].GetGroundStateMass()); }
inline void ResetResidual() { reactants[3].SetVectorCartesian(0,0,0, reactants[3].GetGroundStateMass()); }
private:
void CalculateDecay(); //target -> light_decay (eject) + heavy_decay(resid)
void CalculateReaction(); //target + project -> eject + resid
void CalculateReactionThetaLab();
void CalculateReactionThetaCM();
Nucleus reactants[4]; //0=target, 1=projectile, 2=ejectile, 3=residual
LayeredTarget* target; //not owned by Reaction
double m_bke, m_theta, m_phi, m_ex;
int rxnLayer;
int m_eject_theta_type;
bool decayFlag, nuc_initFlag, resid_elossFlag;
static constexpr int lab = 0;
static constexpr int center_of_mass = 1;
};
}
#endif

View File

@ -1,52 +0,0 @@
#ifndef ROOTPLOTTER_H
#define ROOTPLOTTER_H
#include <vector>
#include <string>
#include "Nucleus.h"
#include "RxnType.h"
#include "MaskFile.h"
#include <THashTable.h>
#include <TH1.h>
#include <TH2.h>
#include <TGraph.h>
struct GraphData {
std::string name;
std::string title;
std::vector<double> xvec;
std::vector<double> yvec;
int color;
};
class RootPlotter {
public:
RootPlotter();
~RootPlotter();
inline void ClearTable() { table->Clear(); };
inline THashTable* GetTable() {
GenerateGraphs();
return table;
};
void FillData(const Mask::Nucleus& nuc, double detKE = 0.0, const std::string& modifier = "");
void FillCorrelations(const Mask::MaskFileData& data, Mask::RxnType type);
void FillCorrelationsDetected(const Mask::MaskFileData& data, Mask::RxnType type);
private:
THashTable* table;
void GenerateGraphs();
void MyFill(const std::string& name, const std::string& title, int bins, float min, float max, double val);
void MyFill(const std::string& name, const std::string& title, int binsx, float minx, float maxx, int binsy, float miny, float maxy, double valx, double valy);
void MyFill(const std::string& name, const std::string& title, double valx, double valy, int color); //TGraph
std::vector<TGraph*> garbage_collection;
std::vector<GraphData> graphs;
static constexpr double rad2deg = 180.0/M_PI;
};
#endif

View File

@ -1,78 +0,0 @@
/*
Classes which define rotations about the x, y, and z axes. Using these,
any arbitrary orientation can be described. Methods implemented for vector multiplication
as well as generating the inverse of the rotation.
*/
#ifndef ROTATION_H
#define ROTATION_H
#include "Vec3.h"
namespace Mask {
class XRotation {
public:
XRotation();
XRotation(double ang);
~XRotation();
Vec3 Rotate(const Vec3& vector);
inline void SetAngle(double ang) { m_angle = ang; GenerateMatrix(); }
inline XRotation GetInverse() { return XRotation(-m_angle); }
inline Vec3 operator*(const Vec3& vector) {
double x = m_matrix[0][0]*vector[0] + m_matrix[0][1]*vector[1] + m_matrix[0][2]*vector[2];
double y = m_matrix[1][0]*vector[0] + m_matrix[1][1]*vector[1] + m_matrix[1][2]*vector[2];
double z = m_matrix[2][0]*vector[0] + m_matrix[2][1]*vector[1] + m_matrix[2][2]*vector[2];
return Vec3(x, y, z);
}
private:
void GenerateMatrix();
double m_angle;
double m_matrix[3][3];
};
class YRotation {
public:
YRotation();
YRotation(double ang);
~YRotation();
Vec3 Rotate(const Vec3& vector);
inline void SetAngle(double ang) { m_angle = ang; GenerateMatrix(); }
inline YRotation GetInverse() { return YRotation(-m_angle); }
inline Vec3 operator*(const Vec3& vector) {
double x = m_matrix[0][0]*vector[0] + m_matrix[0][1]*vector[1] + m_matrix[0][2]*vector[2];
double y = m_matrix[1][0]*vector[0] + m_matrix[1][1]*vector[1] + m_matrix[1][2]*vector[2];
double z = m_matrix[2][0]*vector[0] + m_matrix[2][1]*vector[1] + m_matrix[2][2]*vector[2];
return Vec3(x, y, z);
}
private:
void GenerateMatrix();
double m_angle;
double m_matrix[3][3];
};
class ZRotation {
public:
ZRotation();
ZRotation(double ang);
~ZRotation();
Vec3 Rotate(const Vec3& vector);
inline void SetAngle(double ang) { m_angle = ang; GenerateMatrix(); }
inline ZRotation GetInverse() { return ZRotation(-m_angle); }
inline Vec3 operator*(const Vec3& vector) {
double x = m_matrix[0][0]*vector[0] + m_matrix[0][1]*vector[1] + m_matrix[0][2]*vector[2];
double y = m_matrix[1][0]*vector[0] + m_matrix[1][1]*vector[1] + m_matrix[1][2]*vector[2];
double z = m_matrix[2][0]*vector[0] + m_matrix[2][1]*vector[1] + m_matrix[2][2]*vector[2];
return Vec3(x, y, z);
}
private:
void GenerateMatrix();
double m_angle;
double m_matrix[3][3];
};
}
#endif

View File

@ -1,177 +0,0 @@
/*
Class which represents a single MMM detector in the SABRE array at FSU. Origial code by KGH, re-written by
GWM.
Distances in meters, angles in radians.
The channel arrays have four points, one for each corner. The corners are
as follows, as if looking BACK along beam (i.e. from the target's pov):
0---------------------1
| |
| | x
| | <-----
| | |
| | |
3---------------------2 y
(z is hence positive along beam direction)
The channel numbers, also as looking back from target pov, are:
>> rings are 0 -- 15 from inner to outer:
15 -------------------
14 -------------------
13 -------------------
.
.
.
2 -------------------
1 -------------------
0 -------------------
>> wedges are 0 -- 7 moving counterclockwise:
7 6 ... 1 0
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
>> Note that the detector starts centered on the x-axis (central phi = 0) untilted, and then is rotated to wherever the frick
it is supposed to go; phi = 90 is centered on y axis, pointing down towards the bottom of the scattering chamber
-- GWM, Dec 2020; based on the og code from kgh
*/
#ifndef SABREDETECTOR_H
#define SABREDETECTOR_H
#include <vector>
#include <cmath>
#include "Vec3.h"
#include "Rotation.h"
class SabreDetector {
public:
SabreDetector();
SabreDetector(int detID, double Rin, double Rout, double deltaPhi_flat, double phiCentral, double tiltFromVert, double zdist, double xdist=0, double ydist=0);
~SabreDetector();
/*Return coordinates of the corners of each ring/wedge in SABRE*/
inline Mask::Vec3 GetRingFlatCoords(int ch, int corner) { return CheckRingLocation(ch, corner) ? m_ringCoords_flat[ch][corner] : Mask::Vec3(); };
inline Mask::Vec3 GetWedgeFlatCoords(int ch, int corner) { return CheckWedgeLocation(ch, corner) ? m_wedgeCoords_flat[ch][corner] : Mask::Vec3(); };
inline Mask::Vec3 GetRingTiltCoords(int ch, int corner) { return CheckRingLocation(ch, corner) ? m_ringCoords_tilt[ch][corner] : Mask::Vec3(); };
inline Mask::Vec3 GetWedgeTiltCoords(int ch, int corner) { return CheckWedgeLocation(ch, corner) ? m_wedgeCoords_tilt[ch][corner] : Mask::Vec3(); };
Mask::Vec3 GetTrajectoryCoordinates(double theta, double phi);
std::pair<int, int> GetTrajectoryRingWedge(double theta, double phi);
Mask::Vec3 GetHitCoordinates(int ringch, int wedgech);
/*Basic getters*/
inline int GetNumberOfWedges() { return m_nWedges; };
inline int GetNumberOfRings() { return m_nRings; };
inline double GetInnerRadius() { return m_Rinner; };
inline double GetOuterRadius() { return m_Router; };
inline double GetPhiCentral() { return m_phiCentral; };
inline double GetTiltAngle() { return m_tilt; };
inline Mask::Vec3 GetTranslation() { return m_translation; };
inline Mask::Vec3 GetNormTilted() { return TransformToTiltedFrame(m_norm_flat); };
int GetDetectorID() { return m_detectorID; }
private:
/*Class constants*/
static constexpr int m_nRings = 16;
static constexpr int m_nWedges = 8;
static constexpr double deg2rad = M_PI/180.0;
/*These are implicitly the width of the spacing between detector active strips*/
static constexpr double POSITION_TOL = 0.0001; //0.1 mm position tolerance
static constexpr double ANGULAR_TOL = 0.1*M_PI/180.0; // 0.1 degree angular tolerance
void CalculateCorners();
/*Performs the transformation to the tilted,rotated,translated frame of the SABRE detector*/
inline Mask::Vec3 TransformToTiltedFrame(Mask::Vec3& vector) { return (m_ZRot*(m_YRot*vector)) + m_translation; };
/*Determine if a given channel/corner combo is valid*/
inline bool CheckRingChannel(int ch) { return (ch<m_nRings && ch>=0) ? true : false; };
inline bool CheckWedgeChannel(int ch) { return (ch<m_nWedges && ch >=0) ? true : false; };
inline bool CheckCorner(int corner) { return (corner < 4 && corner >=0) ? true : false; };
inline bool CheckRingLocation(int ch, int corner) { return CheckRingChannel(ch) && CheckCorner(corner); };
inline bool CheckWedgeLocation(int ch, int corner) { return CheckWedgeChannel(ch) && CheckCorner(corner); };
/*
For all of the calculations, need a limit precision to determine if values are actually equal or not
Here the approx. size of the strip spacing is used as the precision.
*/
inline bool CheckPositionEqual(double val1,double val2) { return fabs(val1-val2) > POSITION_TOL ? false : true; };
inline bool CheckAngleEqual(double val1,double val2) { return fabs(val1-val2) > ANGULAR_TOL ? false : true; };
/*Determine if a hit is within the bulk detector*/
inline bool IsInside(double r, double phi) {
double phi_1 = m_deltaPhi_flat/2.0;
double phi_2 = M_PI*2.0 - m_deltaPhi_flat/2.0;
return (((r > m_Rinner && r < m_Router) || CheckPositionEqual(r, m_Rinner) || CheckPositionEqual(r, m_Router)) && (phi > phi_2 || phi < phi_1 || CheckAngleEqual(phi, phi_1) || CheckAngleEqual(phi, phi_2)));
};
/*
For a given radius/phi are you inside of a given ring/wedge channel,
or are you on the spacing between these channels
*/
inline bool IsRing(double r, int ringch) {
double ringtop = m_Rinner + m_deltaR_flat_ring*(ringch + 1);
double ringbottom = m_Rinner + m_deltaR_flat_ring*(ringch);
return (r>ringbottom && r<ringtop);
};
inline bool IsRingTopEdge(double r, int ringch) {
double ringtop = m_Rinner + m_deltaR_flat_ring*(ringch + 1);
return CheckPositionEqual(r, ringtop);
};
inline bool IsRingBottomEdge(double r, int ringch) {
double ringbottom = m_Rinner + m_deltaR_flat_ring*(ringch);
return CheckPositionEqual(r, ringbottom);
};
inline bool IsWedge(double phi, int wedgech) {
double wedgetop = -m_deltaPhi_flat/2.0 + m_deltaPhi_flat_wedge*(wedgech+1);
double wedgebottom = -m_deltaPhi_flat/2.0 + m_deltaPhi_flat_wedge*(wedgech);
return ((phi>wedgebottom && phi<wedgetop));
};
inline bool IsWedgeTopEdge(double phi, int wedgech) {
double wedgetop = -m_deltaPhi_flat/2.0 + m_deltaPhi_flat_wedge*(wedgech+1);
return CheckAngleEqual(phi, wedgetop);
}
inline bool IsWedgeBottomEdge(double phi, int wedgech) {
double wedgebottom = -m_deltaPhi_flat/2.0 + m_deltaPhi_flat_wedge*(wedgech);
return CheckAngleEqual(phi, wedgebottom);
}
/*Class data*/
double m_Router, m_Rinner, m_deltaPhi_flat, m_phiCentral, m_tilt;
Mask::Vec3 m_translation;
Mask::YRotation m_YRot;
Mask::ZRotation m_ZRot;
double m_deltaR_flat, m_deltaR_flat_ring, m_deltaPhi_flat_wedge;
Mask::Vec3 m_norm_flat;
int m_detectorID;
std::vector<std::vector<Mask::Vec3>> m_ringCoords_flat, m_wedgeCoords_flat;
std::vector<std::vector<Mask::Vec3>> m_ringCoords_tilt, m_wedgeCoords_tilt;
};
#endif

View File

@ -1,51 +0,0 @@
#ifndef SABREEFFICIENCY_H
#define SABREEFFICIENCY_H
#include "MaskFile.h"
#include "DetectorEfficiency.h"
#include "SabreDetector.h"
#include "Target.h"
#include "SabreDeadChannelMap.h"
#include "Nucleus.h"
class SabreEfficiency : public DetectorEfficiency {
public:
SabreEfficiency();
~SabreEfficiency();
void SetDeadChannelMap(std::string& filename) { dmap.LoadMapfile(filename); };
void CalculateEfficiency(const std::string& inputname, const std::string& outputname, const std::string& statsname) override;
void DrawDetectorSystem(const std::string& filename) override;
double RunConsistencyCheck() override;
private:
std::pair<bool,double> IsSabre(Mask::Nucleus& nucleus);
void CountCoincidences(const Mask::MaskFileData& data, std::vector<int>& counts, Mask::RxnType rxn_type);
std::vector<SabreDetector> detectors;
Mask::Target deadlayer;
Mask::Target sabre_eloss;
Mask::Target degrader;
SabreDeadChannelMap dmap;
//Sabre constants
const double INNER_R = 0.0326;
const double OUTER_R = 0.1351;
const double TILT = 40.0;
const double DIST_2_TARG = -0.1245;
const double PHI_COVERAGE = 54.4; //delta phi for each det
const double PHI0 = 306.0; //center phi values for each det in array
const double PHI1 = 18.0; //# is equal to detID in channel map
const double PHI2 = 234.0;
const double PHI3 = 162.0;
const double PHI4 = 90.0;
const double DEG2RAD = M_PI/180.0;
static constexpr double DEADLAYER_THIN = 50 * 1e-7 * 2.3296 * 1e6; // ug/cm^2 (50 nm thick * density)
static constexpr double SABRE_THICKNESS = 500 * 1e-4 * 2.3926 * 1e6; // ug/cm^2 (500 um thick * density)
static constexpr double DEGRADER_THICKNESS = 70.0 * 1.0e-4 * 16.69 * 1e6; //tantalum degrader (70 um thick)
const double ENERGY_THRESHOLD = 0.25; //in MeV
};
#endif

View File

@ -1,30 +0,0 @@
/*
Stopwatch.h
Simple class designed to provide timing info on parts of the process.
Only for use in development.
Written by G.W. McCann Oct. 2020
*/
#ifndef STOPWATCH_H
#define STOPWATCH_H
#include <chrono>
class Stopwatch {
public:
Stopwatch();
~Stopwatch();
void Start();
void Stop();
double GetElapsedSeconds();
double GetElapsedMilliseconds();
private:
using Time = std::chrono::high_resolution_clock::time_point;
using Clock = std::chrono::high_resolution_clock;
Time start_time, stop_time;
};
#endif

View File

@ -1,76 +0,0 @@
#ifndef __STRIP_DETECTOR_H
#define __STRIP_DETECTOR_H
// +z is along beam axis
// +y is vertically "downward" in the lab frame
//angles must be in radians, but distances can be whatever
//PROVIDED all input distances are the same
//Front strips from largest y to smallest y
//Back strips from lowest z to highest z
#include <cmath>
#include <vector>
#include <random>
#include "Vec3.h"
#include "Rotation.h"
#include "RandomGenerator.h"
struct StripHit
{
int front_strip_index=-1;
int back_strip_index=-1;
double front_ratio=0.0;
};
class StripDetector {
public:
StripDetector(int ns, double len, double wid, double cphi, double cz, double crho);
~StripDetector();
inline Mask::Vec3 GetFrontStripCoordinates(int stripch, int corner) { return front_strip_coords[stripch][corner]; }
inline Mask::Vec3 GetBackStripCoordinates(int stripch, int corner) { return back_strip_coords[stripch][corner]; }
inline Mask::Vec3 GetRotatedFrontStripCoordinates(int stripch, int corner) { return rotated_front_strip_coords[stripch][corner]; }
inline Mask::Vec3 GetRotatedBackStripCoordinates(int stripch, int corner) { return rotated_back_strip_coords[stripch][corner]; }
inline Mask::Vec3 GetNormRotated() { return zRot*m_norm_unrot; }
inline void TurnOnRandomizedCoordinates() { rndmFlag = true; }
inline void TurnOffRandomizedCoordinates() { rndmFlag = false; }
Mask::Vec3 GetHitCoordinates(int front_stripch, double front_strip_ratio);
StripHit GetChannelRatio(double theta, double phi);
private:
inline bool ValidChannel(int f) { return ((f >= 0 && f < num_strips) ? true : false); };
inline bool ValidRatio(double r) { return ((r >= -1 && r <= 1) ? true : false); };
void CalculateCorners();
int num_strips;
static constexpr int num_corners = 4;
double length; //common to all strips, hence total
double total_width;
double front_strip_width; //assuming equal widths
double back_strip_length; //assuming equal widths
double center_phi; //assuming det centered above x-axis (corresponds to zero phi)
double center_z;
double center_rho; //perpendicular radius from axis
std::vector<std::vector<Mask::Vec3>> front_strip_coords, back_strip_coords;
std::vector<std::vector<Mask::Vec3>> rotated_front_strip_coords, rotated_back_strip_coords;
Mask::Vec3 m_norm_unrot;
Mask::ZRotation zRot;
std::uniform_real_distribution<double> m_uniform_fraction;
bool rndmFlag;
};
#endif

View File

@ -1,50 +0,0 @@
#ifndef THREESTEPSYSTEM_H
#define THREESTEPSYSTEM_H
#include "ReactionSystem.h"
#include "AngularDistribution.h"
namespace Mask {
class ThreeStepSystem : public ReactionSystem {
public:
ThreeStepSystem();
ThreeStepSystem(std::vector<int>& z, std::vector<int>& a);
~ThreeStepSystem();
bool SetNuclei(std::vector<int>& z, std::vector<int>& a) override;
void RunSystem() override;
const std::vector<Nucleus>& GetNuclei() override;
inline void SetDecay1Distribution(const std::string& filename) { decay1dist.ReadDistributionFile(filename); };
inline void SetDecay2Distribution(const std::string& filename) { decay2dist.ReadDistributionFile(filename); };
inline void SetReactionThetaType(int type) { step1.SetEjectileThetaType(type); };
inline const Nucleus& GetTarget() const { return step1.GetTarget(); };
inline const Nucleus& GetProjectile() const { return step1.GetProjectile(); };
inline const Nucleus& GetEjectile() const { return step1.GetEjectile(); };
inline const Nucleus& GetResidual() const { return step1.GetResidual(); };
inline const Nucleus& GetBreakup1() const { return step2.GetEjectile(); };
inline const Nucleus& GetBreakup2() const { return step2.GetResidual(); };
inline const Nucleus& GetBreakup3() const { return step3.GetEjectile(); };
inline const Nucleus& GetBreakup4() const { return step3.GetResidual(); };
inline int GetDecay1AngularMomentum() { return decay1dist.GetL(); };
inline int GetDecay2AngularMomentum(){ return decay2dist.GetL(); };
inline double GetDecay1BranchingRatio() { return decay1dist.GetBranchingRatio(); };
inline double GetDecay2BranchingRatio(){ return decay2dist.GetBranchingRatio(); };
protected:
void LinkTarget() override;
void SetSystemEquation() override;
std::uniform_real_distribution<double> m_phi2Range;
Reaction step1, step2, step3;
AngularDistribution decay1dist, decay2dist;
};
}
#endif

View File

@ -1,45 +0,0 @@
#ifndef TWOSTEPSYSTEM_H
#define TWOSTEPSYSTEM_H
#include "ReactionSystem.h"
#include "AngularDistribution.h"
namespace Mask {
class TwoStepSystem : public ReactionSystem {
public:
TwoStepSystem();
TwoStepSystem(std::vector<int>& z, std::vector<int>& a);
~TwoStepSystem();
bool SetNuclei(std::vector<int>& z, std::vector<int>& a) override;
void RunSystem() override;
const std::vector<Nucleus>& GetNuclei() override;
inline void SetDecay1Distribution(const std::string& filename) { decay1dist.ReadDistributionFile(filename); };
inline void SetReactionThetaType(int type) { step1.SetEjectileThetaType(type); };
inline const Nucleus& GetTarget() const { return step1.GetTarget(); };
inline const Nucleus& GetProjectile() const { return step1.GetProjectile(); };
inline const Nucleus& GetEjectile() const { return step1.GetEjectile(); };
inline const Nucleus& GetResidual() const { return step1.GetResidual(); };
inline const Nucleus& GetBreakup1() const { return step2.GetEjectile(); };
inline const Nucleus& GetBreakup2() const { return step2.GetResidual(); };
inline int GetDecay1AngularMomentum() { return decay1dist.GetL(); };
inline double GetDecay1BranchingRatio() { return decay1dist.GetBranchingRatio(); };
private:
void LinkTarget() override;
void SetSystemEquation() override;
std::uniform_real_distribution<double> m_phi2Range;
Reaction step1, step2;
AngularDistribution decay1dist;
};
}
#endif

View File

@ -1,61 +0,0 @@
/*
Class to represent a 3-space vector in both cartesian and spherical coordinates. Can perform vector
addition, subtraction, and dot product.
--GWM Dec 2020
*/
#ifndef VEC3_H
#define VEC3_H
#include <cmath>
namespace Mask {
class Vec3 {
public:
Vec3();
Vec3(double x, double y, double z);
~Vec3();
void SetVectorCartesian(double x, double y, double z);
void SetVectorSpherical(double r, double theta, double phi);
inline double GetX() const { return m_data[0]; }
inline double GetY() const { return m_data[1]; }
inline double GetZ() const { return m_data[2]; }
inline double GetRho() const { return std::sqrt(std::pow(m_data[0], 2.0) + std::pow(m_data[1], 2.0)); }
inline double GetR() const { return std::sqrt(std::pow(m_data[0], 2.0) + std::pow(m_data[1], 2.0) + std::pow(m_data[2], 2.0)); }
inline double GetTheta() const { return Atan2(GetRho(), GetZ()); }
inline double GetPhi() const {
double phi = Atan2(GetY(), GetX());
if(phi < 0) phi += M_PI*2.0;
return phi;
}
inline const double operator[](int index) const { return index>2 || index<0 ? 0.0 : m_data[index]; }
inline Vec3& operator=(const Vec3& rhs) { SetVectorCartesian(rhs.GetX(), rhs.GetY(), rhs.GetZ()); return *this; }
inline Vec3 operator+(const Vec3& rhs) const { return Vec3(this->GetX()+rhs.GetX(), this->GetY()+rhs.GetY(), this->GetZ()+rhs.GetZ()); }
inline Vec3 operator-(const Vec3& rhs) const { return Vec3(this->GetX()-rhs.GetX(), this->GetY()-rhs.GetY(), this->GetZ()-rhs.GetZ()); }
double Dot(const Vec3& rhs) const;
Vec3 Cross(const Vec3& rhs) const;
private:
//Use instead of std::atan2. Better control over values close to x=0
inline double Atan2(double y, double x) const {
if(x != 0.0) return std::atan2(y, x);
else if(y > 0.0) return M_PI/2.0;
else if(y < 0.0) return -M_PI/2.0;
else return 0.0;
}
double m_data[3];
};
}
#endif

View File

@ -1,69 +0,0 @@
/*
Class which represents a 4-momentum vector. Can perform vector addition, subtraction, dot product
and generate a boost vector to its rest frame as well as apply a boost to itself.
--GWM Dec 2020.
*/
#ifndef VEC4_H
#define VEC4_H
#include <cmath>
namespace Mask {
class Vec4 {
public:
Vec4();
Vec4(double px, double py, double pz, double E);
virtual ~Vec4();
void SetVectorCartesian(double px, double py, double pz, double E);
void SetVectorSpherical(double theta, double phi, double p, double E);
inline double GetE() const { return m_data[3]; }
inline double GetPx() const { return m_data[0]; }
inline double GetPy() const { return m_data[1]; }
inline double GetPz() const { return m_data[2]; }
inline double GetP() const { return std::sqrt(m_data[0]*m_data[0] + m_data[1]*m_data[1] + m_data[2]*m_data[2]); }
inline double GetPxy() const { return std::sqrt(m_data[0]*m_data[0] + m_data[1]*m_data[1]); }
inline double GetTheta() const { return GetPxy() == 0.0 && GetPz() == 0.0 ? 0.0 : Atan2(GetPxy(), GetPz()); }
inline double GetPhi() const {
double phi = Atan2(GetPy(), GetPx());
if(phi<0) phi += 2.0*M_PI;
return GetPx() == 0.0 && GetPy() == 0.0 ? 0.0 : phi;
}
inline double GetInvMass() const { return std::sqrt(GetE()*GetE() - GetP()*GetP()); }
inline double GetKE() const { return GetE() - GetInvMass(); }
inline const double* GetBoost() const { return &m_boost[0]; }
void ApplyBoost(const double* boost);
//Only intended for use in looping access!
inline const double operator[] (int index) const { return index>3 || index < 0 ? 0.0 : m_data[index]; }
inline Vec4& operator=(const Vec4& rhs) { SetVectorCartesian(rhs.GetPx(), rhs.GetPy(), rhs.GetPz(), rhs.GetE()); return *this; }
inline Vec4 operator+(const Vec4& rhs) const { return Vec4(rhs.GetPx()+GetPx(), rhs.GetPy()+GetPy(), rhs.GetPz()+GetPz(), rhs.GetE()+GetE()); }
inline Vec4 operator-(const Vec4& rhs) const { return Vec4(rhs.GetPx()-GetPx(), rhs.GetPy()-GetPy(), rhs.GetPz()-GetPz(), rhs.GetE()-GetE()); }
double Dot(const Vec4& rhs) const;
Vec4 Cross(const Vec4& rhs) const;
private:
void CalcBoostToCM();
//use instead of std::atan2. Better controll over x=0
inline double Atan2(double y, double x) const {
if(x != 0) return std::atan2(y, x);
else if( y > 0 ) return M_PI/2.0;
else if( y < 0 ) return -M_PI/2.0;
else return 0.0;
}
double m_data[4];
double m_boost[3];
};
}
#endif

View File

@ -1,28 +1,27 @@
----------Data Information----------
OutputFile: /data1/gwm17/7BeNov2021/sim/7Bedp_1100keV_beam_50CD2.mask
OutputFile: /media/data/gwm17/mask_tests/10B3Hea_16800keV_5Lia_74B.root
----------Reaction Information----------
ReactionType: TwoStepRxn
Z A (order is target, projectile, ejectile, break1, break3(if pure decay is target, ejectile))
1 2
4 7
1 1
2 4
begin_nuclei(Z,A)
5 10
2 3
2 4
2 4
end_nuclei(Z,A)
----------Target Information----------
NumberOfLayers: 1
begin_layer
Thickness(ug/cm^2): 50
Thickness(ug/cm^2): 74
begin_elements (Z, A, Stoich.)
element 1 2 2
element 6 12 1
element 5 10 1
end_elements
end_layer
----------Sampling Information----------
NumberOfSamples: 100000
BeamMeanEnergy(MeV): 1.1 BeamEnergySigma(MeV): 0.0
EjectileThetaType(0=Lab,1=CM): 1
EjectileThetaMin(deg): 0.0 EjectileThetaMax(deg): 180.0
EjectilePhiMin(deg): 0.0 EjectilePhiMax(deg): 360.0
ResidualExMean(MeV): 0.0 ResidualExSigma(MeV): 0.0
NumberOfSamples: 1000000
BeamMeanEnergy(MeV): 24.0 BeamEnergySigma(MeV): 0.0
EjectileThetaType(0=Lab,1=CM): 0
EjectileThetaMin(deg): 15.0 EjectileThetaMax(deg): 15.0
EjectilePhiMin(deg): 0.0 EjectilePhiMax(deg): 0.0
ResidualExMean(MeV): 16.8 ResidualExSigma(MeV): 0.023
Decay1_DistributionFile: ./etc/isotropic_dist.txt
Decay2_DistributionFile: ./etc/isotropic_dist.txt
--------------------------------------

3
objs/.gitignore vendored
View File

@ -1,3 +0,0 @@
###keep only the directory, not the contents###
*
!.gitignore

View File

@ -1,130 +0,0 @@
workspace "Mask"
configurations {
"Release",
"Debug"
}
project "Mask"
kind "StaticLib"
language "C++"
targetdir "lib"
objdir "objs"
cppdialect "C++17"
files {
"src/Mask/*.cpp",
"include/*.h"
}
includedirs {
"include"
}
filter "configurations:Debug"
symbols "On"
filter "configurations:Release"
optimize "On"
project "RootPlot"
kind "ConsoleApp"
language "C++"
targetdir "bin"
objdir "objs"
cppdialect "c++17"
files {
"src/Plotters/ROOT/RootPlotter.cpp",
"include/*.h"
}
--User specified path to ROOT CERN libraries--
ROOTIncludepath = "/Users/gordon/Cern/root/include"
ROOTLibpath = "/Users/gordon/Cern/root/lib"
includedirs {
"include"
}
sysincludedirs {
ROOTIncludepath
}
libdirs {
"lib/",
ROOTLibpath
}
links {
"Mask", "Gui", "Core", "Imt", "RIO", "Net", "Hist",
"Graf", "Graf3d", "Gpad", "ROOTDataFrame", "ROOTVecOps",
"Tree", "TreePlayer", "Rint", "Postscript", "Matrix",
"Physics", "MathCore", "Thread", "MultiProc", "m", "dl"
}
filter "system:macosx or linux"
linkoptions {
"-pthread"
}
filter "configurations:Debug"
symbols "On"
filter "configurations:Release"
optimize "On"
project "MaskApp"
kind "ConsoleApp"
language "C++"
targetdir "bin"
objdir "objs"
cppdialect "c++17"
files {
"src/MaskApp/*.cpp"
}
includedirs {
"include"
}
links {
"Mask"
}
filter "system:macosx or linux"
linkoptions {
"-pthread"
}
filter "configurations:Debug"
symbols "On"
filter "configurations:Release"
optimize "On"
project "DetectEff"
kind "ConsoleApp"
language "C++"
targetdir "bin"
objdir "objs"
cppdialect "c++17"
files {
"src/Detectors/*.cpp",
"include/*.h"
}
includedirs {
"include"
}
links {
"Mask"
}
filter "configurations:Debug"
symbols "On"
filter "configurations:Release"
optimize "On"

View File

@ -25,7 +25,7 @@ public:
AnasenDeadChannelMap(const std::string& filename);
~AnasenDeadChannelMap();
void LoadMapfile(const std::string& filename);
inline const bool IsValid() const { return valid_flag; }
const bool IsValid() const { return valid_flag; }
const bool IsDead(AnasenDetectorType type, int detIndex, int channel, AnasenDetectorSide side) const;
private:
void InitMap();

View File

@ -3,194 +3,221 @@
#include <iomanip>
#include <iostream>
#include "TFile.h"
#include "TTree.h"
AnasenEfficiency::AnasenEfficiency() :
DetectorEfficiency(), det_silicon(si_thickness)
DetectorEfficiency(), m_detectorEloss({14}, {28}, {1}, s_detectorThickness)
{
for(int i=0; i<n_sx3_per_ring; i++) {
m_Ring1.emplace_back(4, sx3_length, sx3_width, ring_phi[i], ring1_z, ring_rho[i]);
m_Ring1[i].TurnOnRandomizedCoordinates();
m_Ring2.emplace_back(4, sx3_length, sx3_width, ring_phi[i], ring2_z, ring_rho[i]);
m_Ring2[i].TurnOnRandomizedCoordinates();
for(int i=0; i<s_nSX3PerBarrel; i++)
{
m_Ring1.emplace_back(4, s_sx3Length, s_sx3Width, s_barrelPhiList[i], s_barrel1Z, s_barrelRhoList[i]);
m_Ring1[i].SetPixelSmearing(true);
m_Ring2.emplace_back(4, s_sx3Length, s_sx3Width, s_barrelPhiList[i], s_barrel2Z, s_barrelRhoList[i]);
m_Ring2[i].SetPixelSmearing(true);
}
for(int i=0; i<n_qqq; i++) {
m_forwardQQQs.emplace_back(qqq_rinner, qqq_router, qqq_deltaphi, qqq_phi[i], qqq_z[i]);
m_forwardQQQs[i].TurnOnRandomizedCoordinates();
m_backwardQQQs.emplace_back(qqq_rinner, qqq_router, qqq_deltaphi, qqq_phi[i], (-1.0)*qqq_z[i]);
m_backwardQQQs[i].TurnOnRandomizedCoordinates();
for(int i=0; i<s_nQQQ; i++)
{
m_forwardQQQs.emplace_back(s_qqqInnerR, s_qqqOuterR, s_qqqDeltaPhi, s_qqqPhiList[i], s_qqqZList[i]);
m_forwardQQQs[i].SetSmearing(true);
m_backwardQQQs.emplace_back(s_qqqInnerR, s_qqqOuterR, s_qqqDeltaPhi, s_qqqPhiList[i], (-1.0)*s_qqqZList[i]);
m_backwardQQQs[i].SetSmearing(true);
}
std::vector<int> det_z = {14};
std::vector<int> det_a = {28};
std::vector<int> det_stoich = {1};
det_silicon.SetElements(det_z, det_a, det_stoich);
}
AnasenEfficiency::~AnasenEfficiency() {}
void AnasenEfficiency::DrawDetectorSystem(const std::string& filename) {
void AnasenEfficiency::DrawDetectorSystem(const std::string& filename)
{
std::ofstream output(filename);
std::vector<double> x, y, z;
std::vector<double> cx, cy, cz;
Mask::Vec3 coords;
for(int i=0; i<n_sx3_per_ring; i++) {
for(int j=0; j<4; j++) {
for(int k=0; k<4; k++) {
ROOT::Math::XYZPoint coords;
for(int i=0; i<s_nSX3PerBarrel; i++)
{
for(int j=0; j<4; j++)
{
for(int k=0; k<4; k++)
{
coords = m_Ring1[i].GetRotatedFrontStripCoordinates(j, k);
x.push_back(coords.GetX());
y.push_back(coords.GetY());
z.push_back(coords.GetZ());
x.push_back(coords.X());
y.push_back(coords.Y());
z.push_back(coords.Z());
coords = m_Ring1[i].GetRotatedBackStripCoordinates(j, k);
x.push_back(coords.GetX());
y.push_back(coords.GetY());
z.push_back(coords.GetZ());
x.push_back(coords.X());
y.push_back(coords.Y());
z.push_back(coords.Z());
}
coords = m_Ring1[i].GetHitCoordinates(j, 0);
cx.push_back(coords.GetX());
cy.push_back(coords.GetY());
cz.push_back(coords.GetZ());
cx.push_back(coords.X());
cy.push_back(coords.Y());
cz.push_back(coords.Z());
}
}
for(int i=0; i<n_sx3_per_ring; i++) {
for(int j=0; j<4; j++) {
for(int k=0; k<4; k++) {
for(int i=0; i<s_nSX3PerBarrel; i++)
{
for(int j=0; j<4; j++)
{
for(int k=0; k<4; k++)
{
coords = m_Ring2[i].GetRotatedFrontStripCoordinates(j, k);
x.push_back(coords.GetX());
y.push_back(coords.GetY());
z.push_back(coords.GetZ());
x.push_back(coords.X());
y.push_back(coords.Y());
z.push_back(coords.Z());
coords = m_Ring2[i].GetRotatedBackStripCoordinates(j, k);
x.push_back(coords.GetX());
y.push_back(coords.GetY());
z.push_back(coords.GetZ());
x.push_back(coords.X());
y.push_back(coords.Y());
z.push_back(coords.Z());
}
coords = m_Ring2[i].GetHitCoordinates(j, 0);
cx.push_back(coords.GetX());
cy.push_back(coords.GetY());
cz.push_back(coords.GetZ());
cx.push_back(coords.X());
cy.push_back(coords.Y());
cz.push_back(coords.Z());
}
}
for(int i=0; i<n_qqq; i++) {
for(int j=0; j<16; j++) {
for(int k=0; k<4; k++) {
for(int i=0; i<s_nQQQ; i++)
{
for(int j=0; j<16; j++)
{
for(int k=0; k<4; k++)
{
coords = m_forwardQQQs[i].GetRingCoordinates(j, k);
x.push_back(coords.GetX());
y.push_back(coords.GetY());
z.push_back(coords.GetZ());
x.push_back(coords.X());
y.push_back(coords.Y());
z.push_back(coords.Z());
coords = m_forwardQQQs[i].GetWedgeCoordinates(j, k);
x.push_back(coords.GetX());
y.push_back(coords.GetY());
z.push_back(coords.GetZ());
x.push_back(coords.X());
y.push_back(coords.Y());
z.push_back(coords.Z());
}
for(int k=0; k<16; k++) {
for(int k=0; k<16; k++)
{
coords = m_forwardQQQs[i].GetHitCoordinates(j, k);
cx.push_back(coords.GetX());
cy.push_back(coords.GetY());
cz.push_back(coords.GetZ());
cx.push_back(coords.X());
cy.push_back(coords.Y());
cz.push_back(coords.Z());
}
}
}
for(int i=0; i<n_qqq; i++) {
for(int j=0; j<16; j++) {
for(int k=0; k<4; k++) {
for(int i=0; i<s_nQQQ; i++)
{
for(int j=0; j<16; j++)
{
for(int k=0; k<4; k++)
{
coords = m_backwardQQQs[i].GetRingCoordinates(j, k);
x.push_back(coords.GetX());
y.push_back(coords.GetY());
z.push_back(coords.GetZ());
x.push_back(coords.X());
y.push_back(coords.Y());
z.push_back(coords.Z());
coords = m_backwardQQQs[i].GetWedgeCoordinates(j, k);
x.push_back(coords.GetX());
y.push_back(coords.GetY());
z.push_back(coords.GetZ());
x.push_back(coords.X());
y.push_back(coords.Y());
z.push_back(coords.Z());
}
for(int k=0; k<16; k++) {
for(int k=0; k<16; k++)
{
coords = m_backwardQQQs[i].GetHitCoordinates(j, k);
cx.push_back(coords.GetX());
cy.push_back(coords.GetY());
cz.push_back(coords.GetZ());
cx.push_back(coords.X());
cy.push_back(coords.Y());
cz.push_back(coords.Z());
}
}
}
output<<"ANASEN Geometry File -- Coordinates for Detectors"<<std::endl;
for(unsigned int i=0; i<x.size(); i++) {
for(std::size_t i=0; i<x.size(); i++)
output<<x[i]<<" "<<y[i]<<" "<<z[i]<<std::endl;
}
for(unsigned int i=0; i<cx.size(); i++) {
for(std::size_t i=0; i<cx.size(); i++)
output<<cx[i]<<" "<<cy[i]<<" "<<cz[i]<<std::endl;
}
output.close();
}
double AnasenEfficiency::RunConsistencyCheck() {
std::vector<Mask::Vec3> r1_points;
std::vector<Mask::Vec3> r2_points;
std::vector<Mask::Vec3> fqqq_points;
std::vector<Mask::Vec3> bqqq_points;
for(int i=0; i<n_sx3_per_ring; i++) {
for(int j=0; j<4; j++) {
double AnasenEfficiency::RunConsistencyCheck()
{
std::vector<ROOT::Math::XYZPoint> r1_points;
std::vector<ROOT::Math::XYZPoint> r2_points;
std::vector<ROOT::Math::XYZPoint> fqqq_points;
std::vector<ROOT::Math::XYZPoint> bqqq_points;
for(int i=0; i<s_nSX3PerBarrel; i++)
{
for(int j=0; j<4; j++)
r1_points.push_back(m_Ring1[i].GetHitCoordinates(j, 0));
}
}
for(int i=0; i<n_sx3_per_ring; i++) {
for(int j=0; j<4; j++) {
for(int i=0; i<s_nSX3PerBarrel; i++)
{
for(int j=0; j<4; j++)
r2_points.push_back(m_Ring2[i].GetHitCoordinates(j, 0));
}
}
for(int i=0; i<n_qqq; i++) {
for(int j=0; j<16; j++) {
for(int k=0; k<16; k++) {
for(int i=0; i<s_nQQQ; i++)
{
for(int j=0; j<16; j++)
{
for(int k=0; k<16; k++)
fqqq_points.push_back(m_forwardQQQs[i].GetHitCoordinates(j, k));
}
}
}
for(int i=0; i<n_qqq; i++) {
for(int j=0; j<16; j++) {
for(int k=0; k<16; k++) {
for(int i=0; i<s_nQQQ; i++)
{
for(int j=0; j<16; j++)
{
for(int k=0; k<16; k++)
bqqq_points.push_back(m_backwardQQQs[i].GetHitCoordinates(j, k));
}
}
}
int npoints = r1_points.size() + r2_points.size() + fqqq_points.size() + bqqq_points.size();
int count = 0;
Mask::Vec3 coords;
for(auto& point : r1_points) {
for(auto& sx3 : m_Ring1) {
auto result = sx3.GetChannelRatio(point.GetTheta(), point.GetPhi());
std::size_t npoints = r1_points.size() + r2_points.size() + fqqq_points.size() + bqqq_points.size();
std::size_t count = 0;
ROOT::Math::XYZPoint coords;
for(auto& point : r1_points)
{
for(auto& sx3 : m_Ring1)
{
auto result = sx3.GetChannelRatio(point.Theta(), point.Phi());
coords = sx3.GetHitCoordinates(result.front_strip_index, result.front_ratio);
if(IsDoubleEqual(point.GetX(), coords.GetX()) && IsDoubleEqual(point.GetY(), coords.GetY()) && IsDoubleEqual(point.GetZ(), coords.GetZ())) {
if(IsDoubleEqual(point.X(), coords.X()) && IsDoubleEqual(point.Y(), coords.Y()) && IsDoubleEqual(point.Z(), coords.Z()))
{
count++;
break;
}
}
}
for(auto& point : r2_points) {
for(auto& sx3 : m_Ring2) {
auto result = sx3.GetChannelRatio(point.GetTheta(), point.GetPhi());
for(auto& point : r2_points)
{
for(auto& sx3 : m_Ring2)
{
auto result = sx3.GetChannelRatio(point.Theta(), point.Phi());
coords = sx3.GetHitCoordinates(result.front_strip_index, result.front_ratio);
if(IsDoubleEqual(point.GetX(), coords.GetX()) && IsDoubleEqual(point.GetY(), coords.GetY()) && IsDoubleEqual(point.GetZ(), coords.GetZ())) {
if(IsDoubleEqual(point.X(), coords.X()) && IsDoubleEqual(point.Y(), coords.Y()) && IsDoubleEqual(point.Z(), coords.Z()))
{
count++;
break;
}
}
}
for(auto& point : fqqq_points) {
for(auto& qqq : m_forwardQQQs) {
auto result = qqq.GetTrajectoryRingWedge(point.GetTheta(), point.GetPhi());
for(auto& point : fqqq_points)
{
for(auto& qqq : m_forwardQQQs)
{
auto result = qqq.GetTrajectoryRingWedge(point.Theta(), point.Phi());
coords = qqq.GetHitCoordinates(result.first, result.second);
if(IsDoubleEqual(point.GetX(), coords.GetX()) && IsDoubleEqual(point.GetY(), coords.GetY()) && IsDoubleEqual(point.GetZ(), coords.GetZ())) {
if(IsDoubleEqual(point.X(), coords.X()) && IsDoubleEqual(point.Y(), coords.Y()) && IsDoubleEqual(point.Z(), coords.Z()))
{
count++;
break;
}
}
}
for(auto& point : bqqq_points) {
for(auto& qqq : m_backwardQQQs) {
auto result = qqq.GetTrajectoryRingWedge(point.GetTheta(), point.GetPhi());
for(auto& point : bqqq_points)
{
for(auto& qqq : m_backwardQQQs)
{
auto result = qqq.GetTrajectoryRingWedge(point.Theta(), point.Phi());
coords = qqq.GetHitCoordinates(result.first, result.second);
if(IsDoubleEqual(point.GetX(), coords.GetX()) && IsDoubleEqual(point.GetY(), coords.GetY()) && IsDoubleEqual(point.GetZ(), coords.GetZ())) {
if(IsDoubleEqual(point.X(), coords.X()) && IsDoubleEqual(point.Y(), coords.Y()) && IsDoubleEqual(point.Z(), coords.Z()))
{
count++;
break;
}
@ -203,22 +230,23 @@ double AnasenEfficiency::RunConsistencyCheck() {
}
DetectorResult AnasenEfficiency::IsRing1(Mask::Nucleus& nucleus) {
DetectorResult AnasenEfficiency::IsRing1(Mask::Nucleus& nucleus)
{
DetectorResult observation;
double thetaIncident;
for(int i=0; i<n_sx3_per_ring; i++) {
auto result = m_Ring1[i].GetChannelRatio(nucleus.GetTheta(), nucleus.GetPhi());
for(int i=0; i<s_nSX3PerBarrel; i++)
{
auto result = m_Ring1[i].GetChannelRatio(nucleus.vec4.Theta(), nucleus.vec4.Phi());
if(result.front_strip_index != -1 /*&& !dmap.IsDead(AnasenDetectorType::Barrel1, i, result.front_strip_index, AnasenDetectorSide::Front)*/
&& !dmap.IsDead(AnasenDetectorType::Barrel1, i, result.back_strip_index, AnasenDetectorSide::Back))
{
observation.detectFlag = true;
observation.direction = m_Ring1[i].GetHitCoordinates(result.front_strip_index, result.front_ratio);
thetaIncident = std::acos(observation.direction.Dot(m_Ring1[i].GetNormRotated())/observation.direction.GetR());
thetaIncident = std::acos(observation.direction.Dot(m_Ring1[i].GetNormRotated())/observation.direction.R());
if(thetaIncident > M_PI/2.0)
thetaIncident = M_PI - thetaIncident;
observation.energy_deposited = det_silicon.GetEnergyLossTotal(nucleus.GetZ(), nucleus.GetA(), nucleus.GetKE(), thetaIncident);
observation.energy_deposited = m_detectorEloss.GetEnergyLossTotal(nucleus.Z, nucleus.A, nucleus.GetKE(), thetaIncident);
observation.det_name = "R1";
return observation;
}
@ -227,22 +255,23 @@ DetectorResult AnasenEfficiency::IsRing1(Mask::Nucleus& nucleus) {
return observation;
}
DetectorResult AnasenEfficiency::IsRing2(Mask::Nucleus& nucleus) {
DetectorResult AnasenEfficiency::IsRing2(Mask::Nucleus& nucleus)
{
DetectorResult observation;
double thetaIncident;
for(int i=0; i<n_sx3_per_ring; i++) {
auto result = m_Ring2[i].GetChannelRatio(nucleus.GetTheta(), nucleus.GetPhi());
for(int i=0; i<s_nSX3PerBarrel; i++)
{
auto result = m_Ring2[i].GetChannelRatio(nucleus.vec4.Theta(), nucleus.vec4.Phi());
if(result.front_strip_index != -1 /*&& !dmap.IsDead(AnasenDetectorType::Barrel2, i, result.front_strip_index, AnasenDetectorSide::Front)*/
&& !dmap.IsDead(AnasenDetectorType::Barrel2, i, result.back_strip_index, AnasenDetectorSide::Back))
{
observation.detectFlag = true;
observation.direction = m_Ring2[i].GetHitCoordinates(result.front_strip_index, result.front_ratio);
thetaIncident = std::acos(observation.direction.Dot(m_Ring2[i].GetNormRotated())/observation.direction.GetR());
thetaIncident = std::acos(observation.direction.Dot(m_Ring2[i].GetNormRotated())/observation.direction.R());
if(thetaIncident > M_PI/2.0)
thetaIncident = M_PI - thetaIncident;
observation.energy_deposited = det_silicon.GetEnergyLossTotal(nucleus.GetZ(), nucleus.GetA(), nucleus.GetKE(), thetaIncident);
observation.energy_deposited = m_detectorEloss.GetEnergyLossTotal(nucleus.Z, nucleus.A, nucleus.GetKE(), thetaIncident);
observation.det_name = "R2";
return observation;
}
@ -251,40 +280,42 @@ DetectorResult AnasenEfficiency::IsRing2(Mask::Nucleus& nucleus) {
return observation;
}
DetectorResult AnasenEfficiency::IsQQQ(Mask::Nucleus& nucleus) {
DetectorResult AnasenEfficiency::IsQQQ(Mask::Nucleus& nucleus)
{
DetectorResult observation;
double thetaIncident;
for(int i=0; i<n_qqq; i++) {
auto result = m_forwardQQQs[i].GetTrajectoryRingWedge(nucleus.GetTheta(), nucleus.GetPhi());
for(int i=0; i<s_nQQQ; i++)
{
auto result = m_forwardQQQs[i].GetTrajectoryRingWedge(nucleus.vec4.Theta(), nucleus.vec4.Phi());
if(result.first != -1 /*&& !dmap.IsDead(AnasenDetectorType::FQQQ, i, result.first, AnasenDetectorSide::Front)*/ &&
!dmap.IsDead(AnasenDetectorType::FQQQ, i, result.second, AnasenDetectorSide::Back))
{
observation.detectFlag = true;
observation.direction = m_forwardQQQs[i].GetHitCoordinates(result.first, result.second);
thetaIncident = std::acos(observation.direction.Dot(m_forwardQQQs[i].GetNorm())/observation.direction.GetR());
thetaIncident = std::acos(observation.direction.Dot(m_forwardQQQs[i].GetNorm())/observation.direction.R());
if(thetaIncident > M_PI/2.0)
thetaIncident = M_PI - thetaIncident;
observation.energy_deposited = det_silicon.GetEnergyLossTotal(nucleus.GetZ(), nucleus.GetA(), nucleus.GetKE(), thetaIncident);
observation.energy_deposited = m_detectorEloss.GetEnergyLossTotal(nucleus.Z, nucleus.A, nucleus.GetKE(), thetaIncident);
observation.det_name = "FQQQ";
return observation;
}
}
for(int i=0; i<n_qqq; i++) {
auto result = m_backwardQQQs[i].GetTrajectoryRingWedge(nucleus.GetTheta(), nucleus.GetPhi());
for(int i=0; i<s_nQQQ; i++)
{
auto result = m_backwardQQQs[i].GetTrajectoryRingWedge(nucleus.vec4.Theta(), nucleus.vec4.Phi());
if(result.first != -1 /*&& !dmap.IsDead(AnasenDetectorType::BQQQ, i, result.first, AnasenDetectorSide::Front)*/ &&
!dmap.IsDead(AnasenDetectorType::BQQQ, i, result.second, AnasenDetectorSide::Back))
{
observation.detectFlag = true;
observation.direction = m_backwardQQQs[i].GetHitCoordinates(result.first, result.second);
thetaIncident = std::acos(observation.direction.Dot(m_backwardQQQs[i].GetNorm())/observation.direction.GetR());
thetaIncident = std::acos(observation.direction.Dot(m_backwardQQQs[i].GetNorm())/observation.direction.R());
if(thetaIncident > M_PI/2.0)
thetaIncident = M_PI - thetaIncident;
observation.energy_deposited = det_silicon.GetEnergyLossTotal(nucleus.GetZ(), nucleus.GetA(), nucleus.GetKE(), thetaIncident);
observation.energy_deposited = m_detectorEloss.GetEnergyLossTotal(nucleus.Z, nucleus.A, nucleus.GetKE(), thetaIncident);
observation.det_name = "BQQQ";
return observation;
}
@ -293,95 +324,93 @@ DetectorResult AnasenEfficiency::IsQQQ(Mask::Nucleus& nucleus) {
return observation;
}
DetectorResult AnasenEfficiency::IsAnasen(Mask::Nucleus& nucleus) {
DetectorResult AnasenEfficiency::IsAnasen(Mask::Nucleus& nucleus)
{
DetectorResult result;
if(nucleus.GetKE() <= threshold)
if(nucleus.GetKE() <= s_energyThreshold)
return result;
if(!result.detectFlag) {
if(!result.detectFlag)
result = IsRing1(nucleus);
}
if(!result.detectFlag) {
if(!result.detectFlag)
result = IsRing2(nucleus);
}
if(!result.detectFlag) {
if(!result.detectFlag)
result = IsQQQ(nucleus);
}
return result;
}
void AnasenEfficiency::CountCoincidences(const Mask::MaskFileData& data, std::vector<int>& counts, Mask::RxnType rxn_type) {
if (rxn_type == Mask::RxnType::PureDecay && data.detect_flag[1] && data.detect_flag[2])
void AnasenEfficiency::CountCoincidences(const std::vector<Mask::Nucleus>& data, std::vector<int>& counts)
{
if (data.size() == 3 && data[1].isDetected && data[2].isDetected)
{
counts[0]++;
}
else if (rxn_type == Mask::RxnType::OneStepRxn && data.detect_flag[2] && data.detect_flag[3])
else if (data.size() == 4 && data[2].isDetected && data[3].isDetected)
{
counts[0]++;
}
else if(rxn_type == Mask::RxnType::TwoStepRxn)
else if(data.size() == 6)
{
if(data.detect_flag[2] && data.detect_flag[4])
if(data[2].isDetected && data[4].isDetected)
{
counts[0]++;
}
if(data.detect_flag[2] && data.detect_flag[5])
if(data[2].isDetected && data[5].isDetected)
{
counts[1]++;
}
if(data.detect_flag[4] && data.detect_flag[5])
if(data[4].isDetected && data[5].isDetected)
{
counts[2]++;
}
if(data.detect_flag[2] && data.detect_flag[4] && data.detect_flag[5])
if(data[2].isDetected && data[4].isDetected && data[5].isDetected)
{
counts[3]++;
}
}
else if(rxn_type == Mask::RxnType::ThreeStepRxn)
else if(data.size() == 8)
{
if(data.detect_flag[2] && data.detect_flag[4])
if(data[2].isDetected && data[4].isDetected)
{
counts[0]++;
}
if(data.detect_flag[2] && data.detect_flag[6])
if(data[2].isDetected && data[6].isDetected)
{
counts[1]++;
}
if(data.detect_flag[2] && data.detect_flag[7])
if(data[2].isDetected && data[7].isDetected)
{
counts[2]++;
}
if(data.detect_flag[4] && data.detect_flag[6])
if(data[4].isDetected && data[6].isDetected)
{
counts[3]++;
}
if(data.detect_flag[4] && data.detect_flag[7])
if(data[4].isDetected && data[7].isDetected)
{
counts[4]++;
}
if(data.detect_flag[6] && data.detect_flag[7])
if(data[6].isDetected && data[7].isDetected)
{
counts[5]++;
}
if(data.detect_flag[2] && data.detect_flag[4] && data.detect_flag[6])
if(data[2].isDetected && data[4].isDetected && data[6].isDetected)
{
counts[6]++;
}
if(data.detect_flag[2] && data.detect_flag[4] && data.detect_flag[7])
if(data[2].isDetected && data[4].isDetected && data[7].isDetected)
{
counts[7]++;
}
if(data.detect_flag[2] && data.detect_flag[6] && data.detect_flag[7])
if(data[2].isDetected && data[6].isDetected && data[7].isDetected)
{
counts[8]++;
}
if(data.detect_flag[4] && data.detect_flag[6] && data.detect_flag[7])
if(data[4].isDetected && data[6].isDetected && data[7].isDetected)
{
counts[9]++;
}
if(data.detect_flag[2] && data.detect_flag[4] && data.detect_flag[6] && data.detect_flag[7])
if(data[2].isDetected && data[4].isDetected && data[6].isDetected && data[7].isDetected)
{
counts[10]++;
}
@ -401,141 +430,138 @@ void AnasenEfficiency::CalculateEfficiency(const std::string& inputname, const s
std::cout<<"Loading in output from kinematics simulation: "<<inputname<<std::endl;
std::cout<<"Running efficiency calculation..."<<std::endl;
Mask::MaskFile input(inputname, Mask::MaskFile::FileType::read);
Mask::MaskFile output(outputname, Mask::MaskFile::FileType::write);
TFile* input = TFile::Open(inputname.c_str(), "READ");
TFile* output = TFile::Open(outputname.c_str(), "RECREATE");
std::ofstream stats(statsname);
stats<<std::setprecision(5);
Mask::MaskFileHeader header = input.ReadHeader();
output.WriteHeader(header.rxn_type, header.nsamples);
TTree* intree = (TTree*) input->Get("SimTree");
std::vector<Mask::Nucleus>* dataHandle = new std::vector<Mask::Nucleus>();
intree->SetBranchAddress("nuclei", &dataHandle);
output->cd();
TTree* outtree = new TTree("SimTree", "SimTree");
outtree->Branch("nuclei", dataHandle);
input->cd();
stats<<"Efficiency statistics for data from "<<inputname<<" using the ANASEN geometry"<<std::endl;
stats<<"Given in order of target=0, projectile=1, ejectile=2, residual=3, .... etc."<<std::endl;
Mask::MaskFileData data;
intree->GetEntry(1);
std::vector<int> counts;
std::vector<int> coinc_counts;
switch(header.rxn_type) {
case Mask::RxnType::PureDecay:
counts.resize(3, 0);
coinc_counts.resize(1, 0);
break;
case Mask::RxnType::OneStepRxn:
counts.resize(4, 0);
coinc_counts.resize(1, 0);
break;
case Mask::RxnType::TwoStepRxn:
counts.resize(6, 0);
coinc_counts.resize(4, 0);
break;
case Mask::RxnType::ThreeStepRxn:
counts.resize(8, 0);
coinc_counts.resize(11, 0);
break;
counts.resize(dataHandle->size());
switch(counts.size())
{
case 3: coinc_counts.resize(1, 0); break;
case 4: coinc_counts.resize(1, 0); break;
case 6: coinc_counts.resize(4, 0); break;
case 8: coinc_counts.resize(11, 0); break;
default:
{
std::cerr<<"Bad reaction type at AnasenEfficiency::CalculateEfficiency (given value: "<<GetStringFromRxnType(header.rxn_type)<<"). Quiting..."<<std::endl;
input.Close();
output.Close();
std::cerr<<"Bad reaction type at AnasenEfficiency::CalculateEfficiency (given value: "<<counts.size()<<"). Quiting..."<<std::endl;
input->Close();
output->Close();
stats.close();
return;
}
}
int percent5 = header.nsamples*0.05;
int count = 0;
int npercent = 0;
uint64_t nentries = intree->GetEntries();
uint64_t percent5 = nentries*0.05;
uint64_t count = 0;
uint64_t npercent = 0;
Mask::Nucleus nucleus;
int index=0;
while(true) {
if(++count == percent5) {//Show progress every 5%
for(uint64_t i=0; i<nentries; i++)
{
intree->GetEntry(i);
if(++count == percent5)
{//Show progress every 5%
npercent++;
count = 0;
std::cout<<"\rPercent completed: "<<npercent*5<<"%"<<std::flush;
}
data = input.ReadData();
if(data.eof)
break;
for(unsigned int i=0; i<data.Z.size(); i++) {
nucleus.SetIsotope(data.Z[i], data.A[i]);
nucleus.SetVectorSpherical(data.theta[i], data.phi[i], data.p[i], data.E[i]);
auto result = IsAnasen(nucleus);
if(result.detectFlag) {
data.detect_flag[i] = true;
data.KE[i] = result.energy_deposited;
data.theta[i] = result.direction.GetTheta();
data.phi[i] = result.direction.GetPhi();
counts[i]++;
} else if(data.detect_flag[i] == true) {
data.detect_flag[i] = false;
for(std::size_t j=0; j<dataHandle->size(); j++)
{
Mask::Nucleus& nucleus = (*dataHandle)[j];
DetectorResult result = IsAnasen(nucleus);
if(result.detectFlag)
{
nucleus.isDetected = true;
nucleus.detectedKE = result.energy_deposited;
nucleus.detectedTheta = result.direction.Theta();
nucleus.detectedPhi = result.direction.Phi();
counts[j]++;
}
}
CountCoincidences(data, coinc_counts, header.rxn_type);
CountCoincidences(*dataHandle, coinc_counts);
output.WriteData(data);
index++;
outtree->Fill();
}
input->Close();
output->cd();
outtree->Write(outtree->GetName(), TObject::kOverwrite);
output->Close();
input.Close();
output.Close();
delete dataHandle;
stats<<std::setw(10)<<"Index"<<"|"<<std::setw(10)<<"Efficiency"<<std::endl;
stats<<"---------------------"<<std::endl;
for(unsigned int i=0; i<counts.size(); i++) {
stats<<std::setw(10)<<i<<"|"<<std::setw(10)<<((double)counts[i]/header.nsamples)<<std::endl;
for(unsigned int i=0; i<counts.size(); i++)
{
stats<<std::setw(10)<<i<<"|"<<std::setw(10)<<((double)counts[i]/nentries)<<std::endl;
stats<<"---------------------"<<std::endl;
}
stats<<"Coincidence Efficiency"<<std::endl;
stats<<"---------------------"<<std::endl;
if(header.rxn_type == Mask::RxnType::PureDecay)
if(dataHandle->size() == 3)
{
stats<<std::setw(10)<<"1 + 2"<<"|"<<std::setw(10)<<((double)coinc_counts[0]/header.nsamples)<<std::endl;
stats<<std::setw(10)<<"1 + 2"<<"|"<<std::setw(10)<<((double)coinc_counts[0]/nentries)<<std::endl;
stats<<"---------------------"<<std::endl;
}
else if(header.rxn_type == Mask::RxnType::OneStepRxn)
else if(dataHandle->size() == 4)
{
stats<<std::setw(10)<<"2 + 3"<<"|"<<std::setw(10)<<((double)coinc_counts[0]/header.nsamples)<<std::endl;
stats<<std::setw(10)<<"2 + 3"<<"|"<<std::setw(10)<<((double)coinc_counts[0]/nentries)<<std::endl;
stats<<"---------------------"<<std::endl;
}
else if(header.rxn_type == Mask::RxnType::TwoStepRxn)
else if(dataHandle->size() == 6)
{
stats<<std::setw(10)<<"2 + 4"<<"|"<<std::setw(10)<<((double)coinc_counts[0]/header.nsamples)<<std::endl;
stats<<std::setw(10)<<"2 + 4"<<"|"<<std::setw(10)<<((double)coinc_counts[0]/nentries)<<std::endl;
stats<<"---------------------"<<std::endl;
stats<<std::setw(10)<<"2 + 5"<<"|"<<std::setw(10)<<((double)coinc_counts[1]/header.nsamples)<<std::endl;
stats<<std::setw(10)<<"2 + 5"<<"|"<<std::setw(10)<<((double)coinc_counts[1]/nentries)<<std::endl;
stats<<"---------------------"<<std::endl;
stats<<std::setw(10)<<"4 + 5"<<"|"<<std::setw(10)<<((double)coinc_counts[2]/header.nsamples)<<std::endl;
stats<<std::setw(10)<<"4 + 5"<<"|"<<std::setw(10)<<((double)coinc_counts[2]/nentries)<<std::endl;
stats<<"---------------------"<<std::endl;
stats<<std::setw(10)<<"2 + 4 + 5"<<"|"<<std::setw(10)<<((double)coinc_counts[3]/header.nsamples)<<std::endl;
stats<<std::setw(10)<<"2 + 4 + 5"<<"|"<<std::setw(10)<<((double)coinc_counts[3]/nentries)<<std::endl;
stats<<"---------------------"<<std::endl;
}
else if(header.rxn_type == Mask::RxnType::ThreeStepRxn)
else if(dataHandle->size() == 8)
{
stats<<std::setw(10)<<"2 + 4"<<"|"<<std::setw(10)<<((double)coinc_counts[0]/header.nsamples)<<std::endl;
stats<<std::setw(10)<<"2 + 4"<<"|"<<std::setw(10)<<((double)coinc_counts[0]/nentries)<<std::endl;
stats<<"---------------------"<<std::endl;
stats<<std::setw(10)<<"2 + 6"<<"|"<<std::setw(10)<<((double)coinc_counts[1]/header.nsamples)<<std::endl;
stats<<std::setw(10)<<"2 + 6"<<"|"<<std::setw(10)<<((double)coinc_counts[1]/nentries)<<std::endl;
stats<<"---------------------"<<std::endl;
stats<<std::setw(10)<<"2 + 7"<<"|"<<std::setw(10)<<((double)coinc_counts[2]/header.nsamples)<<std::endl;
stats<<std::setw(10)<<"2 + 7"<<"|"<<std::setw(10)<<((double)coinc_counts[2]/nentries)<<std::endl;
stats<<"---------------------"<<std::endl;
stats<<std::setw(10)<<"4 + 6"<<"|"<<std::setw(10)<<((double)coinc_counts[3]/header.nsamples)<<std::endl;
stats<<std::setw(10)<<"4 + 6"<<"|"<<std::setw(10)<<((double)coinc_counts[3]/nentries)<<std::endl;
stats<<"---------------------"<<std::endl;
stats<<std::setw(10)<<"4 + 7"<<"|"<<std::setw(10)<<((double)coinc_counts[4]/header.nsamples)<<std::endl;
stats<<std::setw(10)<<"4 + 7"<<"|"<<std::setw(10)<<((double)coinc_counts[4]/nentries)<<std::endl;
stats<<"---------------------"<<std::endl;
stats<<std::setw(10)<<"6 + 7"<<"|"<<std::setw(10)<<((double)coinc_counts[5]/header.nsamples)<<std::endl;
stats<<std::setw(10)<<"6 + 7"<<"|"<<std::setw(10)<<((double)coinc_counts[5]/nentries)<<std::endl;
stats<<"---------------------"<<std::endl;
stats<<std::setw(10)<<"2 + 4 + 6"<<"|"<<std::setw(10)<<((double)coinc_counts[6]/header.nsamples)<<std::endl;
stats<<std::setw(10)<<"2 + 4 + 6"<<"|"<<std::setw(10)<<((double)coinc_counts[6]/nentries)<<std::endl;
stats<<"---------------------"<<std::endl;
stats<<std::setw(10)<<"2 + 4 + 7"<<"|"<<std::setw(10)<<((double)coinc_counts[7]/header.nsamples)<<std::endl;
stats<<std::setw(10)<<"2 + 4 + 7"<<"|"<<std::setw(10)<<((double)coinc_counts[7]/nentries)<<std::endl;
stats<<"---------------------"<<std::endl;
stats<<std::setw(10)<<"2 + 6 + 7"<<"|"<<std::setw(10)<<((double)coinc_counts[8]/header.nsamples)<<std::endl;
stats<<std::setw(10)<<"2 + 6 + 7"<<"|"<<std::setw(10)<<((double)coinc_counts[8]/nentries)<<std::endl;
stats<<"---------------------"<<std::endl;
stats<<std::setw(10)<<"4 + 6 + 7"<<"|"<<std::setw(10)<<((double)coinc_counts[9]/header.nsamples)<<std::endl;
stats<<std::setw(10)<<"4 + 6 + 7"<<"|"<<std::setw(10)<<((double)coinc_counts[9]/nentries)<<std::endl;
stats<<"---------------------"<<std::endl;
stats<<std::setw(10)<<"2 + 4 + 6 + 7"<<"|"<<std::setw(10)<<((double)coinc_counts[10]/header.nsamples)<<std::endl;
stats<<std::setw(10)<<"2 + 4 + 6 + 7"<<"|"<<std::setw(10)<<((double)coinc_counts[10]/nentries)<<std::endl;
stats<<"---------------------"<<std::endl;
}
stats.close();

View File

@ -0,0 +1,64 @@
#ifndef ANASEN_EFFICIENCY_H
#define ANASEN_EFFICIENCY_H
#include <string>
#include "DetectorEfficiency.h"
#include "StripDetector.h"
#include "QQQDetector.h"
#include "Target.h"
#include "Nucleus.h"
#include "AnasenDeadChannelMap.h"
class AnasenEfficiency : public DetectorEfficiency
{
public:
AnasenEfficiency();
~AnasenEfficiency();
void CalculateEfficiency(const std::string& inputname, const std::string& outputname, const std::string& statsname) override;
void DrawDetectorSystem(const std::string& filename) override;
double RunConsistencyCheck() override;
inline void SetDeadChannelMap(const std::string& filename) { dmap.LoadMapfile(filename); }
private:
DetectorResult IsRing1(Mask::Nucleus& nucleus);
DetectorResult IsRing2(Mask::Nucleus& nucleus);
DetectorResult IsQQQ(Mask::Nucleus& nucleus);
DetectorResult IsAnasen(Mask::Nucleus& nucleus);
void CountCoincidences(const std::vector<Mask::Nucleus>& data, std::vector<int>& counts);
std::vector<StripDetector> m_Ring1, m_Ring2;
std::vector<QQQDetector> m_forwardQQQs;
std::vector<QQQDetector> m_backwardQQQs;
Mask::Target m_detectorEloss;
AnasenDeadChannelMap dmap;
/**** ANASEN geometry constants *****/
static constexpr int s_nSX3PerBarrel = 12;
static constexpr int s_nQQQ = 4;
static constexpr double s_sx3Length = 0.075;
static constexpr double s_sx3Width = 0.04;
static constexpr double s_barrelGap = 0.0254;
static constexpr double s_sx3FrameGap = 0.049; //0.049 is base gap due to frames
static constexpr double s_barrel1Z = s_sx3Length/2.0 + s_sx3FrameGap + s_barrelGap/2.0;
static constexpr double s_barrel2Z = (-1.0)*(s_barrelGap/2.0 + s_sx3Length/2.0);
static constexpr double s_qqqZ = 0.0125 + s_sx3Length + s_sx3FrameGap + s_barrelGap/2.0;
static constexpr double s_qqqInnerR = 0.0501;
static constexpr double s_qqqOuterR = 0.0990;
static constexpr double s_qqqDeltaPhi = 1.52119;
static constexpr double s_qqqZList[4] = {s_qqqZ, s_qqqZ, s_qqqZ, s_qqqZ};
static constexpr double s_qqqPhiList[4] = {5.49779, 0.785398, 2.35619, 3.92699};
static constexpr double s_barrelRhoList[12] = {0.0890601, 0.0889871, 0.0890354, 0.0890247, 0.0890354, 0.0890354, 0.0890247,
0.0890354, 0.0890354, 0.0890247, 0.0890354, 0.0890354};
static constexpr double s_barrelPhiList[12] = {4.97426, 5.49739, 6.02132, 0.261868, 0.785398, 1.30893, 1.83266, 2.35619, 2.87972,
3.40346, 3.92699, 4.45052};
/*************************/
static constexpr double s_energyThreshold = 0.6; //MeV
static constexpr double s_deg2rad = M_PI/180.0;
static constexpr double s_detectorThickness = 1000 * 1e-4 * 2.3926 * 1e6; //thickness in um -> eff thickness in ug/cm^2 for detector
};
#endif

View File

@ -1,18 +1,27 @@
add_executable(DetectEff)
target_include_directories(DetectEff PUBLIC ${MASK_INCLUDE_DIR})
target_include_directories(DetectEff PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/..)
target_sources(DetectEff PUBLIC
AnasenDeadChannelMap.cpp
AnasenDeadChannelMap.h
AnasenEfficiency.cpp
DetectorEfficiency.cpp
AnasenEfficiency.h
main.cpp
DetectorEfficiency.h
QQQDetector.cpp
QQQDetector.h
SabreDeadChannelMap.cpp
SabreDeadChannelMap.h
SabreDetector.cpp
SabreDetector.h
SabreEfficiency.cpp
SabreEfficiency.h
StripDetector.cpp
StripDetector.h
)
target_link_libraries(DetectEff
MaskDict
Mask
catima
)

View File

@ -4,7 +4,18 @@
#include <string>
#include <cmath>
class DetectorEfficiency {
#include "Math/Point3D.h"
struct DetectorResult
{
bool detectFlag = false;
ROOT::Math::XYZPoint direction;
double energy_deposited = 0.0;
std::string det_name = "";
};
class DetectorEfficiency
{
public:
DetectorEfficiency() {};
virtual ~DetectorEfficiency() {};
@ -14,9 +25,9 @@ public:
virtual double RunConsistencyCheck() = 0;
protected:
inline bool IsDoubleEqual(double x, double y) { return std::fabs(x-y) < epsilon ? true : false; };
inline bool IsDoubleEqual(double x, double y) { return std::fabs(x-y) < s_epsilon ? true : false; };
static constexpr double epsilon = 1.0e-6;
static constexpr double s_epsilon = 1.0e-6;
};
#endif

View File

@ -1,107 +1,116 @@
#include "QQQDetector.h"
QQQDetector::QQQDetector(double R_in, double R_out, double deltaPhi, double phiCentral, double z, double x, double y) :
m_Rinner(R_in), m_Router(R_out), m_deltaPhi(deltaPhi), m_phiCentral(phiCentral), m_translation(x,y,z), m_norm(0.0,0.0,1.0), m_uniform_fraction(0.0, 1.0), rndmFlag(false)
m_innerR(R_in), m_outerR(R_out), m_deltaPhi(deltaPhi), m_centralPhi(phiCentral), m_translation(x,y,z), m_norm(0.0,0.0,1.0),
m_uniformFraction(0.0, 1.0), m_isSmearing(false)
{
m_deltaR = (m_Router - m_Rinner)/nrings;
m_deltaPhi_per_wedge = m_deltaPhi/nwedges;
m_ZRot.SetAngle(m_phiCentral);
m_ringCoords.resize(nrings);
m_wedgeCoords.resize(nwedges);
for(auto& ring : m_ringCoords) {
m_deltaR = (m_outerR - m_innerR)/s_nRings;
m_deltaPhiWedge = m_deltaPhi/s_nWedges;
m_zRotation.SetAngle(m_centralPhi);
m_ringCoords.resize(s_nRings);
m_wedgeCoords.resize(s_nWedges);
for(auto& ring : m_ringCoords)
ring.resize(4);
}
for(auto& wedge : m_wedgeCoords) {
for(auto& wedge : m_wedgeCoords)
wedge.resize(4);
}
CalculateCorners();
}
QQQDetector::~QQQDetector() {}
void QQQDetector::CalculateCorners() {
void QQQDetector::CalculateCorners()
{
double x0, x1, x2, x3;
double y0, y1, y2, y3;
double z0, z1, z2, z3;
//Generate flat ring corner coordinates
for(int i=0; i<nrings; i++) {
x0 = (m_Rinner + m_deltaR*(i+1))*std::cos(-m_deltaPhi/2.0);
y0 = (m_Rinner + m_deltaR*(i+1))*std::sin(-m_deltaPhi/2.0);
for(int i=0; i<s_nRings; i++)
{
x0 = (m_innerR + m_deltaR*(i+1))*std::cos(-m_deltaPhi/2.0);
y0 = (m_innerR + m_deltaR*(i+1))*std::sin(-m_deltaPhi/2.0);
z0 = 0.0;
m_ringCoords[i][0].SetVectorCartesian(x0, y0, z0);
m_ringCoords[i][0].SetXYZ(x0, y0, z0);
x1 = (m_Rinner + m_deltaR*(i))*std::cos(-m_deltaPhi/2.0);
y1 = (m_Rinner + m_deltaR*(i))*std::sin(-m_deltaPhi/2.0);
x1 = (m_innerR + m_deltaR*(i))*std::cos(-m_deltaPhi/2.0);
y1 = (m_innerR + m_deltaR*(i))*std::sin(-m_deltaPhi/2.0);
z1 = 0.0;
m_ringCoords[i][1].SetVectorCartesian(x1, y1, z1);
m_ringCoords[i][1].SetXYZ(x1, y1, z1);
x2 = (m_Rinner + m_deltaR*(i))*std::cos(m_deltaPhi/2.0);
y2 = (m_Rinner + m_deltaR*(i))*std::sin(m_deltaPhi/2.0);
x2 = (m_innerR + m_deltaR*(i))*std::cos(m_deltaPhi/2.0);
y2 = (m_innerR + m_deltaR*(i))*std::sin(m_deltaPhi/2.0);
z2 = 0.0;
m_ringCoords[i][2].SetVectorCartesian(x2, y2, z2);
m_ringCoords[i][2].SetXYZ(x2, y2, z2);
x3 = (m_Rinner + m_deltaR*(i+1))*std::cos(m_deltaPhi/2.0);
y3 = (m_Rinner + m_deltaR*(i+1))*std::sin(m_deltaPhi/2.0);
x3 = (m_innerR + m_deltaR*(i+1))*std::cos(m_deltaPhi/2.0);
y3 = (m_innerR + m_deltaR*(i+1))*std::sin(m_deltaPhi/2.0);
z3 = 0.0;
m_ringCoords[i][3].SetVectorCartesian(x3, y3, z3);
m_ringCoords[i][3].SetXYZ(x3, y3, z3);
}
//Generate flat wedge corner coordinates
for(int i=0; i<nwedges; i++) {
x0 = m_Router * std::cos(-m_deltaPhi/2.0 + i*m_deltaPhi_per_wedge);
y0 = m_Router * std::sin(-m_deltaPhi/2.0 + i*m_deltaPhi_per_wedge);
for(int i=0; i<s_nWedges; i++)
{
x0 = m_outerR * std::cos(-m_deltaPhi/2.0 + i*m_deltaPhiWedge);
y0 = m_outerR * std::sin(-m_deltaPhi/2.0 + i*m_deltaPhiWedge);
z0 = 0.0;
m_wedgeCoords[i][0].SetVectorCartesian(x0, y0, z0);
m_wedgeCoords[i][0].SetXYZ(x0, y0, z0);
x1 = m_Rinner * std::cos(-m_deltaPhi/2.0 + i*m_deltaPhi_per_wedge);
y1 = m_Rinner * std::sin(-m_deltaPhi/2.0 + i*m_deltaPhi_per_wedge);
x1 = m_innerR * std::cos(-m_deltaPhi/2.0 + i*m_deltaPhiWedge);
y1 = m_innerR * std::sin(-m_deltaPhi/2.0 + i*m_deltaPhiWedge);
z1 = 0.0;
m_wedgeCoords[i][1].SetVectorCartesian(x1, y1, z1);
m_wedgeCoords[i][1].SetXYZ(x1, y1, z1);
x2 = m_Rinner * std::cos(-m_deltaPhi/2.0 + (i+1)*m_deltaPhi_per_wedge);
y2 = m_Rinner * std::sin(-m_deltaPhi/2.0 + (i+1)*m_deltaPhi_per_wedge);
x2 = m_innerR * std::cos(-m_deltaPhi/2.0 + (i+1)*m_deltaPhiWedge);
y2 = m_innerR * std::sin(-m_deltaPhi/2.0 + (i+1)*m_deltaPhiWedge);
z2 = 0.0;
m_wedgeCoords[i][2].SetVectorCartesian(x2, y2, z2);
m_wedgeCoords[i][2].SetXYZ(x2, y2, z2);
x3 = m_Router * std::cos(-m_deltaPhi/2.0 + (i+1)*m_deltaPhi_per_wedge);
y3 = m_Router * std::sin(-m_deltaPhi/2.0 + (i+1)*m_deltaPhi_per_wedge);
x3 = m_outerR * std::cos(-m_deltaPhi/2.0 + (i+1)*m_deltaPhiWedge);
y3 = m_outerR * std::sin(-m_deltaPhi/2.0 + (i+1)*m_deltaPhiWedge);
z3 = 0.0;
m_wedgeCoords[i][3].SetVectorCartesian(x3, y3, z3);
m_wedgeCoords[i][3].SetXYZ(x3, y3, z3);
}
for(int i=0; i<nrings; i++) {
for(int j=0; j<4; j++) {
for(int i=0; i<s_nRings; i++)
{
for(int j=0; j<4; j++)
m_ringCoords[i][j] = TransformCoordinates(m_ringCoords[i][j]);
}
}
for(int i=0; i<nwedges; i++) {
for(int j=0; j<4; j++) {
for(int i=0; i<s_nWedges; i++)
{
for(int j=0; j<4; j++)
m_wedgeCoords[i][j] = TransformCoordinates(m_wedgeCoords[i][j]);
}
}
}
Mask::Vec3 QQQDetector::GetTrajectoryCoordinates(double theta, double phi) {
double z_to_detector = m_translation.GetZ();
ROOT::Math::XYZPoint QQQDetector::GetTrajectoryCoordinates(double theta, double phi)
{
double z_to_detector = m_translation.Vect().Z();
double rho_traj = z_to_detector*std::tan(theta);
double r_traj = std::sqrt(rho_traj*rho_traj + z_to_detector*z_to_detector);
double min_rho, max_rho, min_phi, max_phi;
Mask::Vec3 result;
ROOT::Math::XYZPoint result;
for(auto& ring : m_ringCoords) {
min_rho = ring[1].GetRho();
max_rho = ring[0].GetRho();
if(rho_traj < max_rho && rho_traj > min_rho) {
for(auto& wedge : m_wedgeCoords) {
min_phi = wedge[0].GetPhi();
max_phi = wedge[3].GetPhi();
if(phi < min_phi && phi < max_phi) {
result.SetVectorSpherical(r_traj, theta, phi);
for(auto& ring : m_ringCoords)
{
min_rho = ring[1].Rho();
max_rho = ring[0].Rho();
if(rho_traj < max_rho && rho_traj > min_rho)
{
for(auto& wedge : m_wedgeCoords)
{
min_phi = wedge[0].Phi();
max_phi = wedge[3].Phi();
if(phi < min_phi && phi < max_phi)
{
result.SetXYZ(std::sin(theta)*std::cos(phi)*r_traj,
std::sin(theta)*std::sin(phi)*r_traj,
std::cos(theta)*r_traj);
break;
}
}
@ -109,55 +118,57 @@ Mask::Vec3 QQQDetector::GetTrajectoryCoordinates(double theta, double phi) {
}
return result;
}
std::pair<int,int> QQQDetector::GetTrajectoryRingWedge(double theta, double phi) {
double z_to_detector = m_translation.GetZ();
std::pair<int,int> QQQDetector::GetTrajectoryRingWedge(double theta, double phi)
{
double z_to_detector = m_translation.Vect().Z();
double rho_traj = z_to_detector*std::tan(theta);
double min_rho, max_rho, min_phi, max_phi;
for(int r=0; r<nrings; r++) {
for(int r=0; r<s_nRings; r++)
{
auto& ring = m_ringCoords[r];
min_rho = ring[1].GetRho();
max_rho = ring[0].GetRho();
if(rho_traj < max_rho && rho_traj > min_rho) {
for(int w=0; w<nwedges; w++) {
min_rho = ring[1].Rho();
max_rho = ring[0].Rho();
if(rho_traj < max_rho && rho_traj > min_rho)
{
for(int w=0; w<s_nWedges; w++)
{
auto& wedge = m_wedgeCoords[w];
min_phi = wedge[0].GetPhi();
max_phi = wedge[3].GetPhi();
if(phi > min_phi && phi < max_phi) {
min_phi = wedge[0].Phi();
max_phi = wedge[3].Phi();
if(phi > min_phi && phi < max_phi)
return std::make_pair(r, w);
}
}
}
}
return std::make_pair(-1, -1);
}
Mask::Vec3 QQQDetector::GetHitCoordinates(int ringch, int wedgech) {
ROOT::Math::XYZPoint QQQDetector::GetHitCoordinates(int ringch, int wedgech)
{
if(!CheckChannel(ringch) || !CheckChannel(wedgech))
return Mask::Vec3();
return ROOT::Math::XYZPoint();
double r_center, phi_center;
if(rndmFlag)
if(m_isSmearing)
{
r_center = m_Rinner + (m_uniform_fraction(Mask::RandomGenerator::GetInstance().GetGenerator())+ringch)*m_deltaR;
phi_center = -m_deltaPhi/2.0 + (m_uniform_fraction(Mask::RandomGenerator::GetInstance().GetGenerator())+wedgech)*m_deltaPhi_per_wedge;
r_center = m_innerR + (m_uniformFraction(Mask::RandomGenerator::GetInstance().GetGenerator())+ringch)*m_deltaR;
phi_center = -m_deltaPhi/2.0 + (m_uniformFraction(Mask::RandomGenerator::GetInstance().GetGenerator())+wedgech)*m_deltaPhiWedge;
}
else
{
r_center = m_Rinner + (0.5+ringch)*m_deltaR;
phi_center = -m_deltaPhi/2.0 + (0.5+wedgech)*m_deltaPhi_per_wedge;
r_center = m_innerR + (0.5+ringch)*m_deltaR;
phi_center = -m_deltaPhi/2.0 + (0.5+wedgech)*m_deltaPhiWedge;
}
double x = r_center*std::cos(phi_center);
double y = r_center*std::sin(phi_center);
double z = 0;
Mask::Vec3 hit(x, y, z);
ROOT::Math::XYZPoint hit(x, y, z);
return TransformCoordinates(hit);
}

View File

@ -0,0 +1,65 @@
/*
QQQDetector.h
Class implementing geometry for QQQDetector where the detector is perpendicular to the beam axis.
Detector is first generated centered on the x-axis (phi=0)
Coordinate convention : +z is downstream, -z is upstream. +y is vertically down in the lab.
*/
#ifndef QQQDETECTOR_H
#define QQQDETECTOR_H
#include <cmath>
#include <vector>
#include "RandomGenerator.h"
#include "Math/Point3D.h"
#include "Math/Vector3D.h"
#include "Math/RotationZ.h"
#include "Math/Translation3D.h"
class QQQDetector
{
public:
QQQDetector(double R_in, double R_out, double deltaPhi, double phiCentral, double z, double x=0, double y=0);
~QQQDetector();
const ROOT::Math::XYZPoint& GetRingCoordinates(int ringch, int corner) { return m_ringCoords[ringch][corner]; }
const ROOT::Math::XYZPoint& GetWedgeCoordinates(int wedgech, int corner) { return m_wedgeCoords[wedgech][corner]; }
const ROOT::Math::XYZVector& GetNorm() { return m_norm; }
ROOT::Math::XYZPoint GetTrajectoryCoordinates(double theta, double phi);
std::pair<int, int> GetTrajectoryRingWedge(double theta, double phi);
ROOT::Math::XYZPoint GetHitCoordinates(int ringch, int wedgech);
void SetSmearing(bool isSmearing) { m_isSmearing = isSmearing; }
int GetNumberOfRings() { return s_nRings; }
int GetNumberOfWedges() { return s_nWedges; }
private:
bool CheckChannel(int ch) { return (ch >=0 && ch < s_nRings); }
bool CheckCorner(int corner) { return (corner >=0 && corner < 4); }
void CalculateCorners();
ROOT::Math::XYZPoint TransformCoordinates(ROOT::Math::XYZPoint& vector) { return m_translation * (m_zRotation * vector) ; }
double m_innerR;
double m_outerR;
double m_deltaR;
double m_deltaPhi;
double m_deltaPhiWedge;
double m_centralPhi;
std::vector<std::vector<ROOT::Math::XYZPoint>> m_ringCoords, m_wedgeCoords;
ROOT::Math::Translation3D m_translation;
ROOT::Math::XYZVector m_norm;
ROOT::Math::RotationZ m_zRotation;
std::uniform_real_distribution<double> m_uniformFraction;
bool m_isSmearing;
static constexpr int s_nRings = 16;
static constexpr int s_nWedges = 16;
static constexpr double s_deg2rad = M_PI/180.0;
};
#endif

View File

@ -53,126 +53,133 @@
#include "SabreDetector.h"
SabreDetector::SabreDetector() :
m_Router(0.1351), m_Rinner(0.0326), m_deltaPhi_flat(54.4*deg2rad), m_phiCentral(0.0), m_tilt(0.0), m_translation(0.,0.,0.), m_norm_flat(0,0,1.0),
m_detectorID(-1)
m_outerR(0.1351), m_innerR(0.0326), m_deltaPhiFlat(54.4*s_deg2rad), m_centerPhi(0.0), m_tilt(0.0),
m_translation(0.,0.,0.), m_norm(0,0,1.0), m_detectorID(-1)
{
m_YRot.SetAngle(m_tilt);
m_ZRot.SetAngle(m_phiCentral);
m_yRotation.SetAngle(m_tilt);
m_zRotation.SetAngle(m_centerPhi);
//Initialize the coordinate arrays
m_ringCoords_flat.resize(m_nRings);
m_ringCoords_tilt.resize(m_nRings);
m_wedgeCoords_flat.resize(m_nWedges);
m_wedgeCoords_tilt.resize(m_nWedges);
for(int i=0; i<m_nRings; i++) {
m_ringCoords_flat[i].resize(4);
m_ringCoords_tilt[i].resize(4);
m_flatRingCoords.resize(s_nRings);
m_tiltRingCoords.resize(s_nRings);
m_flatWedgeCoords.resize(s_nWedges);
m_tiltWedgeCoords.resize(s_nWedges);
for(int i=0; i<s_nRings; i++) {
m_flatRingCoords[i].resize(4);
m_tiltRingCoords[i].resize(4);
}
for(int i=0; i<m_nWedges; i++) {
m_wedgeCoords_flat[i].resize(4);
m_wedgeCoords_tilt[i].resize(4);
for(int i=0; i<s_nWedges; i++) {
m_flatWedgeCoords[i].resize(4);
m_tiltWedgeCoords[i].resize(4);
}
m_deltaR_flat = m_Router - m_Rinner;
m_deltaR_flat_ring = m_deltaR_flat/m_nRings;
m_deltaRFlat = m_outerR - m_innerR;
m_deltaRFlatRing = m_deltaRFlat/s_nRings;
m_deltaPhiFlatWedge = m_deltaPhiFlat/s_nWedges;
CalculateCorners();
}
SabreDetector::SabreDetector(int detID, double Rin, double Rout, double deltaPhi_flat, double phiCentral, double tiltFromVert, double zdist, double xdist, double ydist) :
m_Router(Rout), m_Rinner(Rin), m_deltaPhi_flat(deltaPhi_flat), m_phiCentral(phiCentral), m_tilt(tiltFromVert), m_translation(xdist, ydist, zdist), m_norm_flat(0,0,1.0),
m_detectorID(detID)
SabreDetector::SabreDetector(int detID, double Rin, double Rout, double deltaPhi_flat, double phiCentral,
double tiltFromVert, double zdist, double xdist, double ydist) :
m_outerR(Rout), m_innerR(Rin), m_deltaPhiFlat(deltaPhi_flat), m_centerPhi(phiCentral), m_tilt(tiltFromVert),
m_translation(xdist, ydist, zdist), m_norm(0,0,1.0), m_detectorID(detID)
{
m_YRot.SetAngle(m_tilt);
m_ZRot.SetAngle(m_phiCentral);
m_yRotation.SetAngle(m_tilt);
m_zRotation.SetAngle(m_centerPhi);
//Initialize coordinate arrays
m_ringCoords_flat.resize(m_nRings);
m_ringCoords_tilt.resize(m_nRings);
m_wedgeCoords_flat.resize(m_nWedges);
m_wedgeCoords_tilt.resize(m_nWedges);
for(int i=0; i<m_nRings; i++) {
m_ringCoords_flat[i].resize(4);
m_ringCoords_tilt[i].resize(4);
m_flatRingCoords.resize(s_nRings);
m_tiltRingCoords.resize(s_nRings);
m_flatWedgeCoords.resize(s_nWedges);
m_tiltWedgeCoords.resize(s_nWedges);
for(int i=0; i<s_nRings; i++)
{
m_flatRingCoords[i].resize(4);
m_tiltRingCoords[i].resize(4);
}
for(int i=0; i<m_nWedges; i++) {
m_wedgeCoords_flat[i].resize(4);
m_wedgeCoords_tilt[i].resize(4);
for(int i=0; i<s_nWedges; i++)
{
m_flatWedgeCoords[i].resize(4);
m_tiltWedgeCoords[i].resize(4);
}
m_deltaR_flat = m_Router - m_Rinner;
m_deltaR_flat_ring = m_deltaR_flat/m_nRings;
m_deltaPhi_flat_wedge = m_deltaPhi_flat/m_nWedges;
m_deltaRFlat = m_outerR - m_innerR;
m_deltaRFlatRing = m_deltaRFlat/s_nRings;
m_deltaPhiFlatWedge = m_deltaPhiFlat/s_nWedges;
CalculateCorners();
}
SabreDetector::~SabreDetector() {}
void SabreDetector::CalculateCorners() {
void SabreDetector::CalculateCorners()
{
double x0, x1, x2, x3;
double y0, y1, y2, y3;
double z0, z1, z2, z3;
//Generate flat ring corner coordinates
for(int i=0; i<m_nRings; i++) {
x0 = (m_Rinner + m_deltaR_flat_ring*(i+1))*std::cos(-m_deltaPhi_flat/2.0);
y0 = (m_Rinner + m_deltaR_flat_ring*(i+1))*std::sin(-m_deltaPhi_flat/2.0);
for(int i=0; i<s_nRings; i++)
{
x0 = (m_innerR + m_deltaRFlatRing*(i+1))*std::cos(-m_deltaPhiFlat/2.0);
y0 = (m_innerR + m_deltaRFlatRing*(i+1))*std::sin(-m_deltaPhiFlat/2.0);
z0 = 0.0;
m_ringCoords_flat[i][0].SetVectorCartesian(x0, y0, z0);
m_flatRingCoords[i][0].SetXYZ(x0, y0, z0);
x1 = (m_Rinner + m_deltaR_flat_ring*(i))*std::cos(-m_deltaPhi_flat/2.0);
y1 = (m_Rinner + m_deltaR_flat_ring*(i))*std::sin(-m_deltaPhi_flat/2.0);
x1 = (m_innerR + m_deltaRFlatRing*(i))*std::cos(-m_deltaPhiFlat/2.0);
y1 = (m_innerR + m_deltaRFlatRing*(i))*std::sin(-m_deltaPhiFlat/2.0);
z1 = 0.0;
m_ringCoords_flat[i][1].SetVectorCartesian(x1, y1, z1);
m_flatRingCoords[i][1].SetXYZ(x1, y1, z1);
x2 = (m_Rinner + m_deltaR_flat_ring*(i))*std::cos(m_deltaPhi_flat/2.0);
y2 = (m_Rinner + m_deltaR_flat_ring*(i))*std::sin(m_deltaPhi_flat/2.0);
x2 = (m_innerR + m_deltaRFlatRing*(i))*std::cos(m_deltaPhiFlat/2.0);
y2 = (m_innerR + m_deltaRFlatRing*(i))*std::sin(m_deltaPhiFlat/2.0);
z2 = 0.0;
m_ringCoords_flat[i][2].SetVectorCartesian(x2, y2, z2);
m_flatRingCoords[i][2].SetXYZ(x2, y2, z2);
x3 = (m_Rinner + m_deltaR_flat_ring*(i+1))*std::cos(m_deltaPhi_flat/2.0);
y3 = (m_Rinner + m_deltaR_flat_ring*(i+1))*std::sin(m_deltaPhi_flat/2.0);
x3 = (m_innerR + m_deltaRFlatRing*(i+1))*std::cos(m_deltaPhiFlat/2.0);
y3 = (m_innerR + m_deltaRFlatRing*(i+1))*std::sin(m_deltaPhiFlat/2.0);
z3 = 0.0;
m_ringCoords_flat[i][3].SetVectorCartesian(x3, y3, z3);
m_flatRingCoords[i][3].SetXYZ(x3, y3, z3);
}
//Generate flat wedge corner coordinates
for(int i=0; i<m_nWedges; i++) {
x0 = m_Router * std::cos(-m_deltaPhi_flat/2.0 + i*m_deltaPhi_flat_wedge);
y0 = m_Router * std::sin(-m_deltaPhi_flat/2.0 + i*m_deltaPhi_flat_wedge);
for(int i=0; i<s_nWedges; i++)
{
x0 = m_outerR * std::cos(-m_deltaPhiFlat/2.0 + i*m_deltaPhiFlatWedge);
y0 = m_outerR * std::sin(-m_deltaPhiFlat/2.0 + i*m_deltaPhiFlatWedge);
z0 = 0.0;
m_wedgeCoords_flat[i][0].SetVectorCartesian(x0, y0, z0);
m_flatWedgeCoords[i][0].SetXYZ(x0, y0, z0);
x1 = m_Rinner * std::cos(-m_deltaPhi_flat/2.0 + i*m_deltaPhi_flat_wedge);
y1 = m_Rinner * std::sin(-m_deltaPhi_flat/2.0 + i*m_deltaPhi_flat_wedge);
x1 = m_innerR * std::cos(-m_deltaPhiFlat/2.0 + i*m_deltaPhiFlatWedge);
y1 = m_innerR * std::sin(-m_deltaPhiFlat/2.0 + i*m_deltaPhiFlatWedge);
z1 = 0.0;
m_wedgeCoords_flat[i][1].SetVectorCartesian(x1, y1, z1);
m_flatWedgeCoords[i][1].SetXYZ(x1, y1, z1);
x2 = m_Rinner * std::cos(-m_deltaPhi_flat/2.0 + (i+1)*m_deltaPhi_flat_wedge);
y2 = m_Rinner * std::sin(-m_deltaPhi_flat/2.0 + (i+1)*m_deltaPhi_flat_wedge);
x2 = m_innerR * std::cos(-m_deltaPhiFlat/2.0 + (i+1)*m_deltaPhiFlatWedge);
y2 = m_innerR * std::sin(-m_deltaPhiFlat/2.0 + (i+1)*m_deltaPhiFlatWedge);
z2 = 0.0;
m_wedgeCoords_flat[i][2].SetVectorCartesian(x2, y2, z2);
m_flatWedgeCoords[i][2].SetXYZ(x2, y2, z2);
x3 = m_Router * std::cos(-m_deltaPhi_flat/2.0 + (i+1)*m_deltaPhi_flat_wedge);
y3 = m_Router * std::sin(-m_deltaPhi_flat/2.0 + (i+1)*m_deltaPhi_flat_wedge);
x3 = m_outerR * std::cos(-m_deltaPhiFlat/2.0 + (i+1)*m_deltaPhiFlatWedge);
y3 = m_outerR * std::sin(-m_deltaPhiFlat/2.0 + (i+1)*m_deltaPhiFlatWedge);
z3 = 0.0;
m_wedgeCoords_flat[i][3].SetVectorCartesian(x3, y3, z3);
m_flatWedgeCoords[i][3].SetXYZ(x3, y3, z3);
}
//Generate tilted rings
for(int i=0; i<m_nRings; i++) {
for(int j=0; j<4; j++) {
m_ringCoords_tilt[i][j] = TransformToTiltedFrame(m_ringCoords_flat[i][j]);
}
for(int i=0; i<s_nRings; i++)
{
for(int j=0; j<4; j++)
m_tiltRingCoords[i][j] = Transform(m_flatRingCoords[i][j]);
}
//Generate tilted wedges
for(int i=0; i<m_nWedges; i++) {
for(int j=0; j<4; j++) {
m_wedgeCoords_tilt[i][j] = TransformToTiltedFrame(m_wedgeCoords_flat[i][j]);
}
for(int i=0; i<s_nWedges; i++)
{
for(int j=0; j<4; j++)
m_tiltWedgeCoords[i][j] = Transform(m_flatWedgeCoords[i][j]);
}
}
@ -193,35 +200,37 @@ void SabreDetector::CalculateCorners() {
!NOTE: This currently only applies to a configuration where there is no translation in x & y. The math becomes significantly messier in these cases.
Also, don't use tan(). It's behavior near PI/2 makes it basically useless for these.
*/
Mask::Vec3 SabreDetector::GetTrajectoryCoordinates(double theta, double phi) {
if(m_translation.GetX() != 0.0 || m_translation.GetY() != 0.0) {
return Mask::Vec3();
}
ROOT::Math::XYZPoint SabreDetector::GetTrajectoryCoordinates(double theta, double phi)
{
if(m_translation.Vect().X() != 0.0 || m_translation.Vect().Y() != 0.0)
return ROOT::Math::XYZPoint();
//Calculate the *potential* phi in the flat detector
double phi_numerator = std::cos(m_tilt)*(std::sin(phi)*std::cos(m_phiCentral) - std::sin(m_phiCentral)*std::cos(phi));
double phi_denominator = std::cos(m_phiCentral)*std::cos(phi) + std::sin(m_phiCentral)*std::sin(phi);
double phi_numerator = std::cos(m_tilt)*(std::sin(phi)*std::cos(m_centerPhi) - std::sin(m_centerPhi)*std::cos(phi));
double phi_denominator = std::cos(m_centerPhi)*std::cos(phi) + std::sin(m_centerPhi)*std::sin(phi);
double phi_flat = std::atan2(phi_numerator, phi_denominator);
if(phi_flat < 0) phi_flat += M_PI*2.0;
if(phi_flat < 0)
phi_flat += M_PI*2.0;
//Calculate the *potential* R in the flat detector
double r_numerator = m_translation.GetZ()*std::cos(phi)*std::sin(theta);
double r_denominator = std::cos(phi_flat)*std::cos(m_phiCentral)*std::cos(m_tilt)*std::cos(theta) - std::sin(phi_flat)*std::sin(m_phiCentral)*std::cos(theta) - std::cos(phi_flat)*std::sin(m_tilt)*std::cos(phi)*std::sin(theta);
double r_numerator = m_translation.Vect().Z()*std::cos(phi)*std::sin(theta);
double r_denominator = std::cos(phi_flat)*std::cos(m_centerPhi)*std::cos(m_tilt)*std::cos(theta) -
std::sin(phi_flat)*std::sin(m_centerPhi)*std::cos(theta) -
std::cos(phi_flat)*std::sin(m_tilt)*std::cos(phi)*std::sin(theta);
double r_flat = r_numerator/r_denominator;
//Calculate the distance from the origin to the hit on the detector
double R_to_detector = (r_flat*std::cos(phi_flat)*std::sin(m_tilt) + m_translation.GetZ())/std::cos(theta);
double R_to_detector = (r_flat*std::cos(phi_flat)*std::sin(m_tilt) + m_translation.Vect().Z())/std::cos(theta);
double xhit = R_to_detector*std::sin(theta)*std::cos(phi);
double yhit = R_to_detector*std::sin(theta)*std::sin(phi);
double zhit = R_to_detector*std::cos(theta);
//Check to see if our flat coords fall inside the flat detector
if(IsInside(r_flat, phi_flat)) {
return Mask::Vec3(xhit, yhit, zhit);
} else {
return Mask::Vec3();
}
if(IsInside(r_flat, phi_flat))
return ROOT::Math::XYZPoint(xhit, yhit, zhit);
else
return ROOT::Math::XYZPoint();
}
/*
@ -241,20 +250,23 @@ Mask::Vec3 SabreDetector::GetTrajectoryCoordinates(double theta, double phi) {
!NOTE: This currently only applies to a configuration where there is no translation in x & y. The math becomes significantly messier in these cases.
Also, don't use tan(). It's behavior near PI/2 makes it basically useless for these.
*/
std::pair<int, int> SabreDetector::GetTrajectoryRingWedge(double theta, double phi) {
if(m_translation.GetX() != 0.0 || m_translation.GetY() != 0.0) {
std::pair<int, int> SabreDetector::GetTrajectoryRingWedge(double theta, double phi)
{
if(m_translation.Vect().X() != 0.0 || m_translation.Vect().Y() != 0.0)
return std::make_pair(-1, -1);
}
//Calculate the *potential* phi in the flat detector
double phi_numerator = std::cos(m_tilt)*(std::sin(phi)*std::cos(m_phiCentral) - std::sin(m_phiCentral)*std::cos(phi));
double phi_denominator = std::cos(m_phiCentral)*std::cos(phi) + std::sin(m_phiCentral)*std::sin(phi);
double phi_numerator = std::cos(m_tilt)*(std::sin(phi)*std::cos(m_centerPhi) - std::sin(m_centerPhi)*std::cos(phi));
double phi_denominator = std::cos(m_centerPhi)*std::cos(phi) + std::sin(m_centerPhi)*std::sin(phi);
double phi_flat = std::atan2(phi_numerator, phi_denominator);
if(phi_flat < 0) phi_flat += M_PI*2.0;
if(phi_flat < 0)
phi_flat += M_PI*2.0;
//Calculate the *potential* R in the flat detector
double r_numerator = m_translation.GetZ()*std::cos(phi)*std::sin(theta);
double r_denominator = std::cos(phi_flat)*std::cos(m_phiCentral)*std::cos(m_tilt)*std::cos(theta) - std::sin(phi_flat)*std::sin(m_phiCentral)*std::cos(theta) - std::cos(phi_flat)*std::sin(m_tilt)*std::cos(phi)*std::sin(theta);
double r_numerator = m_translation.Vect().Z()*std::cos(phi)*std::sin(theta);
double r_denominator = std::cos(phi_flat)*std::cos(m_centerPhi)*std::cos(m_tilt)*std::cos(theta) -
std::sin(phi_flat)*std::sin(m_centerPhi)*std::cos(theta) -
std::cos(phi_flat)*std::sin(m_tilt)*std::cos(phi)*std::sin(theta);
double r_flat = r_numerator/r_denominator;
//Calculate the distance from the origin to the hit on the detector
@ -262,31 +274,41 @@ std::pair<int, int> SabreDetector::GetTrajectoryRingWedge(double theta, double p
//Check to see if our flat coords fall inside the flat detector
if(IsInside(r_flat, phi_flat)) {
if(IsInside(r_flat, phi_flat))
{
int ringch, wedgech;
if(phi_flat > M_PI) phi_flat -= 2.0*M_PI; //Need phi in terms of [-deltaPhi_flat/2, deltaPhi_flat/2]
for(int i=0; i<m_nRings; i++) {
if(IsRingTopEdge(r_flat, i) || IsRingBottomEdge(r_flat, i)) { //If it falls in the interstrip spacing, kill it
if(phi_flat > M_PI)
phi_flat -= 2.0*M_PI; //Need phi in terms of [-deltaPhi_flat/2, deltaPhi_flat/2]
for(int i=0; i<s_nRings; i++)
{
if(IsRingTopEdge(r_flat, i) || IsRingBottomEdge(r_flat, i))
{ //If it falls in the interstrip spacing, kill it
ringch = -1;
break;
} else if(IsRing(r_flat, i)) {
}
else if(IsRing(r_flat, i))
{
ringch = i;
break;
}
}
for(int i=0; i<m_nWedges; i++) {
if(IsWedgeTopEdge(phi_flat, i) || IsWedgeBottomEdge(phi_flat, i)){ //If it falls in the interstrip spacing, kill it
for(int i=0; i<s_nWedges; i++)
{
if(IsWedgeTopEdge(phi_flat, i) || IsWedgeBottomEdge(phi_flat, i))
{ //If it falls in the interstrip spacing, kill it
wedgech = -1;
break;
} else if(IsWedge(phi_flat, i)) {
}
else if(IsWedge(phi_flat, i))
{
wedgech = i;
break;
}
}
return std::make_pair(ringch, wedgech);
} else {
return std::make_pair(-1,-1);
}
else
return std::make_pair(-1,-1);
}
/*
@ -295,18 +317,18 @@ std::pair<int, int> SabreDetector::GetTrajectoryRingWedge(double theta, double p
randomly wiggle the point within the pixel. Method intended for use with data, or
to smear out simulated data to mimic real data.
*/
Mask::Vec3 SabreDetector::GetHitCoordinates(int ringch, int wedgech) {
if(!CheckRingChannel(ringch) || !CheckWedgeChannel(wedgech)) {
return Mask::Vec3();
}
ROOT::Math::XYZPoint SabreDetector::GetHitCoordinates(int ringch, int wedgech)
{
if(!CheckRingChannel(ringch) || !CheckWedgeChannel(wedgech))
return ROOT::Math::XYZPoint();
double r_center = m_Rinner + (0.5+ringch)*m_deltaR_flat_ring;
double phi_center = -m_deltaPhi_flat/2.0 + (0.5+wedgech)*m_deltaPhi_flat_wedge;
double r_center = m_innerR + (0.5+ringch)*m_deltaRFlatRing;
double phi_center = -m_deltaPhiFlat/2.0 + (0.5+wedgech)*m_deltaPhiFlatWedge;
double x = r_center*std::cos(phi_center);
double y = r_center*std::sin(phi_center);
double z = 0;
Mask::Vec3 hit(x, y, z);
ROOT::Math::XYZPoint hit(x, y, z);
return TransformToTiltedFrame(hit);
return Transform(hit);
}

View File

@ -0,0 +1,189 @@
/*
Class which represents a single MMM detector in the SABRE array at FSU. Origial code by KGH, re-written by
GWM.
Distances in meters, angles in radians.
The channel arrays have four points, one for each corner. The corners are
as follows, as if looking BACK along beam (i.e. from the target's pov):
0---------------------1
| |
| | x
| | <-----
| | |
| | |
3---------------------2 y
(z is hence positive along beam direction)
The channel numbers, also as looking back from target pov, are:
>> rings are 0 -- 15 from inner to outer:
15 -------------------
14 -------------------
13 -------------------
.
.
.
2 -------------------
1 -------------------
0 -------------------
>> wedges are 0 -- 7 moving counterclockwise:
7 6 ... 1 0
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
>> Note that the detector starts centered on the x-axis (central phi = 0) untilted, and then is rotated to wherever the frick
it is supposed to go; phi = 90 is centered on y axis, pointing down towards the bottom of the scattering chamber
-- GWM, Dec 2020; based on the og code from kgh
*/
#ifndef SABREDETECTOR_H
#define SABREDETECTOR_H
#include <vector>
#include <cmath>
#include "Math/Point3D.h"
#include "Math/Vector3D.h"
#include "Math/RotationZ.h"
#include "Math/RotationY.h"
#include "Math/Translation3D.h"
class SabreDetector {
public:
SabreDetector();
SabreDetector(int detID, double Rin, double Rout, double deltaPhi_flat, double phiCentral, double tiltFromVert, double zdist, double xdist=0, double ydist=0);
~SabreDetector();
/*Return coordinates of the corners of each ring/wedge in SABRE*/
const ROOT::Math::XYZPoint& GetRingFlatCoords(int ch, int corner) const { return m_flatRingCoords[ch][corner]; }
const ROOT::Math::XYZPoint& GetWedgeFlatCoords(int ch, int corner) const { return m_flatWedgeCoords[ch][corner]; }
const ROOT::Math::XYZPoint& GetRingTiltCoords(int ch, int corner) const { return m_tiltRingCoords[ch][corner]; }
const ROOT::Math::XYZPoint& GetWedgeTiltCoords(int ch, int corner) const { return m_tiltWedgeCoords[ch][corner]; }
ROOT::Math::XYZPoint GetTrajectoryCoordinates(double theta, double phi);
std::pair<int, int> GetTrajectoryRingWedge(double theta, double phi);
ROOT::Math::XYZPoint GetHitCoordinates(int ringch, int wedgech);
int GetNumberOfWedges() { return s_nWedges; }
int GetNumberOfRings() { return s_nRings; }
ROOT::Math::XYZVector GetNormTilted() { return m_zRotation*(m_yRotation*m_norm); }
int GetDetectorID() { return m_detectorID; }
private:
void CalculateCorners();
/*Performs the transformation to the tilted,rotated,translated frame of the SABRE detector*/
ROOT::Math::XYZPoint Transform(const ROOT::Math::XYZPoint& vector) { return m_translation*(m_zRotation*(m_yRotation*vector)); };
/*Determine if a given channel/corner combo is valid*/
bool CheckRingChannel(int ch) { return (ch<s_nRings && ch>=0) ? true : false; };
bool CheckWedgeChannel(int ch) { return (ch<s_nWedges && ch >=0) ? true : false; };
bool CheckCorner(int corner) { return (corner < 4 && corner >=0) ? true : false; };
bool CheckRingLocation(int ch, int corner) { return CheckRingChannel(ch) && CheckCorner(corner); };
bool CheckWedgeLocation(int ch, int corner) { return CheckWedgeChannel(ch) && CheckCorner(corner); };
/*
For all of the calculations, need a limit precision to determine if values are actually equal or not
Here the approx. size of the strip spacing is used as the precision.
*/
bool CheckPositionEqual(double val1,double val2) { return fabs(val1-val2) > s_positionTol ? false : true; };
bool CheckAngleEqual(double val1,double val2) { return fabs(val1-val2) > s_angularTol ? false : true; };
/*Determine if a hit is within the bulk detector*/
bool IsInside(double r, double phi)
{
double phi_1 = m_deltaPhiFlat/2.0;
double phi_2 = M_PI*2.0 - m_deltaPhiFlat/2.0;
return (((r > m_innerR && r < m_outerR) || CheckPositionEqual(r, m_innerR) || CheckPositionEqual(r, m_outerR))
&& (phi > phi_2 || phi < phi_1 || CheckAngleEqual(phi, phi_1) || CheckAngleEqual(phi, phi_2)));
};
/*
For a given radius/phi are you inside of a given ring/wedge channel,
or are you on the spacing between these channels
*/
bool IsRing(double r, int ringch)
{
double ringtop = m_innerR + m_deltaRFlatRing*(ringch + 1);
double ringbottom = m_innerR + m_deltaRFlatRing*(ringch);
return (r>ringbottom && r<ringtop);
};
inline bool IsRingTopEdge(double r, int ringch)
{
double ringtop = m_innerR + m_deltaRFlatRing*(ringch + 1);
return CheckPositionEqual(r, ringtop);
};
inline bool IsRingBottomEdge(double r, int ringch)
{
double ringbottom = m_innerR + m_deltaRFlatRing*(ringch);
return CheckPositionEqual(r, ringbottom);
};
inline bool IsWedge(double phi, int wedgech)
{
double wedgetop = -m_deltaPhiFlat/2.0 + m_deltaPhiFlatWedge*(wedgech+1);
double wedgebottom = -m_deltaPhiFlat/2.0 + m_deltaPhiFlatWedge*(wedgech);
return ((phi>wedgebottom && phi<wedgetop));
};
inline bool IsWedgeTopEdge(double phi, int wedgech)
{
double wedgetop = -m_deltaPhiFlat/2.0 + m_deltaPhiFlatWedge*(wedgech+1);
return CheckAngleEqual(phi, wedgetop);
}
inline bool IsWedgeBottomEdge(double phi, int wedgech)
{
double wedgebottom = -m_deltaPhiFlat/2.0 + m_deltaPhiFlatWedge*(wedgech);
return CheckAngleEqual(phi, wedgebottom);
}
/*Class constants*/
static constexpr int s_nRings = 16;
static constexpr int s_nWedges = 8;
static constexpr double s_deg2rad = M_PI/180.0;
/*These are implicitly the width of the spacing between detector active strips*/
static constexpr double s_positionTol = 0.0001; //0.1 mm position tolerance
static constexpr double s_angularTol = 0.1*M_PI/180.0; // 0.1 degree angular tolerance
/*Class data*/
double m_outerR;
double m_innerR;
double m_deltaRFlat;
double m_deltaRFlatRing;
double m_deltaPhiFlat;
double m_deltaPhiFlatWedge;
double m_centerPhi;
double m_tilt;
ROOT::Math::Translation3D m_translation;
ROOT::Math::RotationY m_yRotation;
ROOT::Math::RotationZ m_zRotation;
ROOT::Math::XYZVector m_norm;
int m_detectorID;
std::vector<std::vector<ROOT::Math::XYZPoint>> m_flatRingCoords, m_flatWedgeCoords;
std::vector<std::vector<ROOT::Math::XYZPoint>> m_tiltRingCoords, m_tiltWedgeCoords;
};
#endif

View File

@ -1,40 +1,44 @@
#include "SabreEfficiency.h"
#include "MaskFile.h"
#include <fstream>
#include <iostream>
#include <iomanip>
#include "TFile.h"
#include "TTree.h"
SabreEfficiency::SabreEfficiency() :
DetectorEfficiency(), deadlayer(DEADLAYER_THIN), sabre_eloss(SABRE_THICKNESS), degrader(DEGRADER_THICKNESS)
DetectorEfficiency(), m_deadlayerEloss({14}, {28}, {1}, s_deadlayerThickness),
m_detectorEloss({14}, {28}, {1}, s_detectorThickness), m_degraderEloss({73}, {181}, {1}, s_degraderThickness)
{
//Only 0, 1, 4 valid in degrader land
//detectors.emplace_back(0, INNER_R,OUTER_R,PHI_COVERAGE*DEG2RAD,PHI0*DEG2RAD,TILT*DEG2RAD,DIST_2_TARG);
//detectors.emplace_back(1, INNER_R,OUTER_R,PHI_COVERAGE*DEG2RAD,PHI1*DEG2RAD,TILT*DEG2RAD,DIST_2_TARG);
detectors.emplace_back(2, INNER_R,OUTER_R,PHI_COVERAGE*DEG2RAD,PHI2*DEG2RAD,TILT*DEG2RAD,DIST_2_TARG);
detectors.emplace_back(3, INNER_R,OUTER_R,PHI_COVERAGE*DEG2RAD,PHI3*DEG2RAD,TILT*DEG2RAD,DIST_2_TARG);
//detectors.emplace_back(4, INNER_R,OUTER_R,PHI_COVERAGE*DEG2RAD,PHI4*DEG2RAD,TILT*DEG2RAD,DIST_2_TARG);
std::vector<int> dead_z = {14};
std::vector<int> dead_a = {28};
std::vector<int> dead_stoich = {1};
deadlayer.SetElements(dead_z, dead_a, dead_stoich);
sabre_eloss.SetElements(dead_z, dead_a, dead_stoich);
std::vector<int> deg_z = {73};
std::vector<int> deg_a = {181};
std::vector<int> deg_s = {1};
degrader.SetElements(deg_z, deg_a, deg_s);
for(int i=0; i<s_nDets; i++)
m_detectors.emplace_back(i, s_innerR, s_outerR, s_deltaPhi*s_deg2rad, s_centerPhiList[i]*s_deg2rad, s_tilt*s_deg2rad, s_zOffset);
//Only 0, 1, 4 valid in degrader land
m_degradedDetectors[0] = true;
m_degradedDetectors[1] = true;
m_degradedDetectors[2] = false;
m_degradedDetectors[3] = false;
m_degradedDetectors[4] = true;
//Choose who to look at right now. Usually switch on or off degraded/non-degraded.
m_activeDetectors[0] = false;
m_activeDetectors[1] = false;
m_activeDetectors[2] = true;
m_activeDetectors[3] = true;
m_activeDetectors[4] = false;
}
SabreEfficiency::~SabreEfficiency() {}
void SabreEfficiency::CalculateEfficiency(const std::string& inputname, const std::string& outputname, const std::string& statsname) {
void SabreEfficiency::CalculateEfficiency(const std::string& inputname, const std::string& outputname, const std::string& statsname)
{
std::cout<<"----------SABRE Efficiency Calculation----------"<<std::endl;
std::cout<<"Loading in output from kinematics simulation: "<<inputname<<std::endl;
std::cout<<"Running efficiency calculation..."<<std::endl;
if(!dmap.IsValid()) {
if(!m_deadMap.IsValid())
{
std::cerr<<"Unable to run SABRE Efficiency without a dead channel map."<<std::endl;
std::cerr<<"If you have no dead channels, simply make a file that's empty"<<std::endl;
std::cerr<<"Exiting."<<std::endl;
@ -42,137 +46,137 @@ void SabreEfficiency::CalculateEfficiency(const std::string& inputname, const st
}
Mask::MaskFile input(inputname, Mask::MaskFile::FileType::read);
Mask::MaskFile output(outputname, Mask::MaskFile::FileType::write);
TFile* input = TFile::Open(inputname.c_str(), "READ");
TFile* output = TFile::Open(outputname.c_str(), "RECREATE");
std::ofstream stats(statsname);
stats<<std::setprecision(5);
Mask::MaskFileHeader header = input.ReadHeader();
output.WriteHeader(header.rxn_type, header.nsamples);
stats<<"Efficiency statistics for data from "<<inputname<<" using the SPS-SABRE geometry"<<std::endl;
TTree* intree = (TTree*) input->Get("SimTree");
std::vector<Mask::Nucleus>* dataHandle = new std::vector<Mask::Nucleus>();
intree->SetBranchAddress("nuclei", &dataHandle);
output->cd();
TTree* outtree = new TTree("SimTree", "SimTree");
outtree->Branch("nuclei", dataHandle);
input->cd();
stats<<"Efficiency statistics for data from "<<inputname<<" using the ANASEN geometry"<<std::endl;
stats<<"Given in order of target=0, projectile=1, ejectile=2, residual=3, .... etc."<<std::endl;
Mask::MaskFileData data;
Mask::Nucleus nucleus;
intree->GetEntry(1);
std::vector<int> counts;
std::vector<int> coinc_counts;
switch(header.rxn_type) {
case Mask::RxnType::PureDecay:
counts.resize(3, 0);
coinc_counts.resize(1, 0);
break;
case Mask::RxnType::OneStepRxn:
counts.resize(4, 0);
coinc_counts.resize(1, 0);
break;
case Mask::RxnType::TwoStepRxn:
counts.resize(6, 0);
coinc_counts.resize(4, 0);
break;
case Mask::RxnType::ThreeStepRxn:
counts.resize(8, 0);
coinc_counts.resize(11, 0);
break;
counts.resize(dataHandle->size());
switch(counts.size())
{
case 3: coinc_counts.resize(1, 0); break;
case 4: coinc_counts.resize(1, 0); break;
case 6: coinc_counts.resize(4, 0); break;
case 8: coinc_counts.resize(11, 0); break;
default:
{
std::cerr<<"Bad reaction type at AnasenEfficiency::CalculateEfficiency (given value: "<<GetStringFromRxnType(header.rxn_type)<<"). Quiting..."<<std::endl;
input.Close();
output.Close();
std::cerr<<"Bad reaction type at AnasenEfficiency::CalculateEfficiency (given value: "<<counts.size()<<"). Quiting..."<<std::endl;
input->Close();
output->Close();
stats.close();
return;
}
}
int percent5 = header.nsamples*0.05;
int count = 0;
int npercent = 0;
uint64_t nentries = intree->GetEntries();
uint64_t percent5 = nentries*0.05;
uint64_t count = 0;
uint64_t npercent = 0;
while(true) {
if(++count == percent5) {//Show progress every 5%
Mask::Nucleus nucleus;
for(uint64_t i=0; i<nentries; i++)
{
intree->GetEntry(i);
if(++count == percent5)
{//Show progress every 5%
npercent++;
count = 0;
std::cout<<"\rPercent completed: "<<npercent*5<<"%"<<std::flush;
}
data = input.ReadData();
if(data.eof)
break;
for(unsigned int i=0; i<data.Z.size(); i++) {
nucleus.SetIsotope(data.Z[i], data.A[i]);
nucleus.SetVectorSpherical(data.theta[i], data.phi[i], data.p[i], data.E[i]);
auto result = IsSabre(nucleus);
if(result.first) {
data.detect_flag[i] = true;
data.KE[i] = result.second;
counts[i]++;
} else if(data.detect_flag[i] == true) {
data.detect_flag[i] = false;
for(std::size_t j=0; j<dataHandle->size(); j++)
{
Mask::Nucleus& nucleus = (*dataHandle)[j];
DetectorResult result = IsSabre(nucleus);
if(result.detectFlag)
{
nucleus.isDetected = true;
nucleus.detectedKE = result.energy_deposited;
nucleus.detectedTheta = result.direction.Theta();
nucleus.detectedPhi = result.direction.Phi();
counts[j]++;
}
}
CountCoincidences(data, coinc_counts, header.rxn_type);
CountCoincidences(*dataHandle, coinc_counts);
output.WriteData(data);
outtree->Fill();
}
input->Close();
output->cd();
outtree->Write(outtree->GetName(), TObject::kOverwrite);
output->Close();
input.Close();
output.Close();
delete dataHandle;
stats<<std::setw(10)<<"Index"<<"|"<<std::setw(10)<<"Efficiency"<<std::endl;
stats<<"---------------------"<<std::endl;
for(unsigned int i=0; i<counts.size(); i++) {
stats<<std::setw(10)<<i<<"|"<<std::setw(10)<<((double)counts[i]/header.nsamples)<<std::endl;
stats<<std::setw(10)<<i<<"|"<<std::setw(10)<<((double)counts[i]/nentries)<<std::endl;
stats<<"---------------------"<<std::endl;
}
stats<<"Coincidence Efficiency"<<std::endl;
stats<<"---------------------"<<std::endl;
if(header.rxn_type == Mask::RxnType::PureDecay)
if(counts.size() == 3)
{
stats<<std::setw(10)<<"1 + 2"<<"|"<<std::setw(10)<<((double)coinc_counts[0]/header.nsamples)<<std::endl;
stats<<std::setw(10)<<"1 + 2"<<"|"<<std::setw(10)<<((double)coinc_counts[0]/nentries)<<std::endl;
stats<<"---------------------"<<std::endl;
}
else if(header.rxn_type == Mask::RxnType::OneStepRxn)
else if(counts.size() == 4)
{
stats<<std::setw(10)<<"2 + 3"<<"|"<<std::setw(10)<<((double)coinc_counts[0]/header.nsamples)<<std::endl;
stats<<std::setw(10)<<"2 + 3"<<"|"<<std::setw(10)<<((double)coinc_counts[0]/nentries)<<std::endl;
stats<<"---------------------"<<std::endl;
}
else if(header.rxn_type == Mask::RxnType::TwoStepRxn)
else if(counts.size() == 6)
{
stats<<std::setw(10)<<"2 + 4"<<"|"<<std::setw(10)<<((double)coinc_counts[0]/header.nsamples)<<std::endl;
stats<<std::setw(10)<<"2 + 4"<<"|"<<std::setw(10)<<((double)coinc_counts[0]/nentries)<<std::endl;
stats<<"---------------------"<<std::endl;
stats<<std::setw(10)<<"2 + 5"<<"|"<<std::setw(10)<<((double)coinc_counts[1]/header.nsamples)<<std::endl;
stats<<std::setw(10)<<"2 + 5"<<"|"<<std::setw(10)<<((double)coinc_counts[1]/nentries)<<std::endl;
stats<<"---------------------"<<std::endl;
stats<<std::setw(10)<<"4 + 5"<<"|"<<std::setw(10)<<((double)coinc_counts[2]/header.nsamples)<<std::endl;
stats<<std::setw(10)<<"4 + 5"<<"|"<<std::setw(10)<<((double)coinc_counts[2]/nentries)<<std::endl;
stats<<"---------------------"<<std::endl;
stats<<std::setw(10)<<"2 + 4 + 5"<<"|"<<std::setw(10)<<((double)coinc_counts[3]/header.nsamples)<<std::endl;
stats<<std::setw(10)<<"2 + 4 + 5"<<"|"<<std::setw(10)<<((double)coinc_counts[3]/nentries)<<std::endl;
stats<<"---------------------"<<std::endl;
}
else if(header.rxn_type == Mask::RxnType::ThreeStepRxn)
else if(counts.size() == 8)
{
stats<<std::setw(10)<<"2 + 4"<<"|"<<std::setw(10)<<((double)coinc_counts[0]/header.nsamples)<<std::endl;
stats<<std::setw(10)<<"2 + 4"<<"|"<<std::setw(10)<<((double)coinc_counts[0]/nentries)<<std::endl;
stats<<"---------------------"<<std::endl;
stats<<std::setw(10)<<"2 + 6"<<"|"<<std::setw(10)<<((double)coinc_counts[1]/header.nsamples)<<std::endl;
stats<<std::setw(10)<<"2 + 6"<<"|"<<std::setw(10)<<((double)coinc_counts[1]/nentries)<<std::endl;
stats<<"---------------------"<<std::endl;
stats<<std::setw(10)<<"2 + 7"<<"|"<<std::setw(10)<<((double)coinc_counts[2]/header.nsamples)<<std::endl;
stats<<std::setw(10)<<"2 + 7"<<"|"<<std::setw(10)<<((double)coinc_counts[2]/nentries)<<std::endl;
stats<<"---------------------"<<std::endl;
stats<<std::setw(10)<<"4 + 6"<<"|"<<std::setw(10)<<((double)coinc_counts[3]/header.nsamples)<<std::endl;
stats<<std::setw(10)<<"4 + 6"<<"|"<<std::setw(10)<<((double)coinc_counts[3]/nentries)<<std::endl;
stats<<"---------------------"<<std::endl;
stats<<std::setw(10)<<"4 + 7"<<"|"<<std::setw(10)<<((double)coinc_counts[4]/header.nsamples)<<std::endl;
stats<<std::setw(10)<<"4 + 7"<<"|"<<std::setw(10)<<((double)coinc_counts[4]/nentries)<<std::endl;
stats<<"---------------------"<<std::endl;
stats<<std::setw(10)<<"6 + 7"<<"|"<<std::setw(10)<<((double)coinc_counts[5]/header.nsamples)<<std::endl;
stats<<std::setw(10)<<"6 + 7"<<"|"<<std::setw(10)<<((double)coinc_counts[5]/nentries)<<std::endl;
stats<<"---------------------"<<std::endl;
stats<<std::setw(10)<<"2 + 4 + 6"<<"|"<<std::setw(10)<<((double)coinc_counts[6]/header.nsamples)<<std::endl;
stats<<std::setw(10)<<"2 + 4 + 6"<<"|"<<std::setw(10)<<((double)coinc_counts[6]/nentries)<<std::endl;
stats<<"---------------------"<<std::endl;
stats<<std::setw(10)<<"2 + 4 + 7"<<"|"<<std::setw(10)<<((double)coinc_counts[7]/header.nsamples)<<std::endl;
stats<<std::setw(10)<<"2 + 4 + 7"<<"|"<<std::setw(10)<<((double)coinc_counts[7]/nentries)<<std::endl;
stats<<"---------------------"<<std::endl;
stats<<std::setw(10)<<"2 + 6 + 7"<<"|"<<std::setw(10)<<((double)coinc_counts[8]/header.nsamples)<<std::endl;
stats<<std::setw(10)<<"2 + 6 + 7"<<"|"<<std::setw(10)<<((double)coinc_counts[8]/nentries)<<std::endl;
stats<<"---------------------"<<std::endl;
stats<<std::setw(10)<<"4 + 6 + 7"<<"|"<<std::setw(10)<<((double)coinc_counts[9]/header.nsamples)<<std::endl;
stats<<std::setw(10)<<"4 + 6 + 7"<<"|"<<std::setw(10)<<((double)coinc_counts[9]/nentries)<<std::endl;
stats<<"---------------------"<<std::endl;
stats<<std::setw(10)<<"2 + 4 + 6 + 7"<<"|"<<std::setw(10)<<((double)coinc_counts[10]/header.nsamples)<<std::endl;
stats<<std::setw(10)<<"2 + 4 + 6 + 7"<<"|"<<std::setw(10)<<((double)coinc_counts[10]/nentries)<<std::endl;
stats<<"---------------------"<<std::endl;
}
stats.close();
@ -182,58 +186,69 @@ void SabreEfficiency::CalculateEfficiency(const std::string& inputname, const st
std::cout<<"---------------------------------------------"<<std::endl;
}
void SabreEfficiency::DrawDetectorSystem(const std::string& filename) {
void SabreEfficiency::DrawDetectorSystem(const std::string& filename)
{
std::ofstream output(filename);
std::vector<double> ringxs, ringys, ringzs;
std::vector<double> wedgexs, wedgeys, wedgezs;
Mask::Vec3 coords;
for(int i=0; i<5; i++) {
for(int j=0; j<detectors[i].GetNumberOfRings(); j++) {
for(int k=0; k<4; k++) {
coords = detectors[i].GetRingTiltCoords(j, k);
ringxs.push_back(coords.GetX());
ringys.push_back(coords.GetY());
ringzs.push_back(coords.GetZ());
ROOT::Math::XYZPoint coords;
for(int i=0; i<s_nDets; i++)
{
for(int j=0; j<m_detectors[i].GetNumberOfRings(); j++)
{
for(int k=0; k<4; k++)
{
coords = m_detectors[i].GetRingTiltCoords(j, k);
ringxs.push_back(coords.X());
ringys.push_back(coords.Y());
ringzs.push_back(coords.Z());
}
}
}
for(int i=0; i<5; i++) {
for(int j=0; j<detectors[i].GetNumberOfWedges(); j++) {
for(int k=0; k<4; k++) {
coords = detectors[i].GetWedgeTiltCoords(j, k);
wedgexs.push_back(coords.GetX());
wedgeys.push_back(coords.GetY());
wedgezs.push_back(coords.GetZ());
for(int i=0; i<s_nDets; i++)
{
for(int j=0; j<m_detectors[i].GetNumberOfWedges(); j++)
{
for(int k=0; k<4; k++)
{
coords = m_detectors[i].GetWedgeTiltCoords(j, k);
wedgexs.push_back(coords.X());
wedgeys.push_back(coords.Y());
wedgezs.push_back(coords.Z());
}
}
}
output<<"SABRE Geometry File -- Coordinates for Detectors"<<std::endl;
output<<"Edges: x y z"<<std::endl;
for(unsigned int i=0; i<ringxs.size(); i++) {
for(unsigned int i=0; i<ringxs.size(); i++)
output<<ringxs[i]<<" "<<ringys[i]<<" "<<ringzs[i]<<std::endl;
}
for(unsigned int i=0; i<wedgexs.size(); i++) {
for(unsigned int i=0; i<wedgexs.size(); i++)
output<<wedgexs[i]<<" "<<wedgeys[i]<<" "<<wedgezs[i]<<std::endl;
}
output.close();
}
double SabreEfficiency::RunConsistencyCheck() {
double SabreEfficiency::RunConsistencyCheck()
{
double theta, phi;
double npoints = 5.0*16.0*4.0;
int count=0;
for(int h=0; h<5; h++) {
for(int j=0; j<16; j++) {
for(int k=0; k<4; k ++) {
theta = detectors[h].GetRingTiltCoords(j, k).GetTheta();
phi = detectors[h].GetRingTiltCoords(j, k).GetPhi();
for(int i=0; i<5; i++) {
auto channels = detectors[i].GetTrajectoryRingWedge(theta, phi);
if(channels.first != -1) {
ROOT::Math::XYZPoint corner;
for(auto& detector : m_detectors)
{
for(int j=0; j<detector.GetNumberOfRings(); j++)
{
for(int k=0; k<4; k ++) //Check corners
{
corner = detector.GetRingTiltCoords(j, k);
for(int i=0; i<5; i++)
{
auto channels = m_detectors[i].GetTrajectoryRingWedge(corner.Theta(), corner.Phi());
if(channels.first != -1)
{
count++;
}
}
@ -245,105 +260,118 @@ double SabreEfficiency::RunConsistencyCheck() {
}
/*Returns if detected, as well as total energy deposited in SABRE*/
std::pair<bool,double> SabreEfficiency::IsSabre(Mask::Nucleus& nucleus) {
if(nucleus.GetKE() <= ENERGY_THRESHOLD) {
return std::make_pair(false, 0.0);
}
DetectorResult SabreEfficiency::IsSabre(Mask::Nucleus& nucleus)
{
DetectorResult observation;
if(nucleus.GetKE() <= s_energyThreshold)
return observation;
Mask::Vec3 coords;
double thetaIncident, eloss, e_deposited;
double thetaIncident;
double ke = 0.0;
for(auto& detector : detectors) {
auto chan = detector.GetTrajectoryRingWedge(nucleus.GetTheta(), nucleus.GetPhi());
if(chan.first != -1 && chan.second != -1) {
if(dmap.IsDead(detector.GetDetectorID(), chan.first, 0) || dmap.IsDead(detector.GetDetectorID(), chan.second, 1)) break; //dead channel check
coords = detector.GetTrajectoryCoordinates(nucleus.GetTheta(), nucleus.GetPhi());
thetaIncident = std::acos(coords.Dot(detector.GetNormTilted())/(coords.GetR()));
//eloss = degrader.GetEnergyLossTotal(nucleus.GetZ(), nucleus.GetA(), nucleus.GetKE(), thetaIncident);
//ke = nucleus.GetKE() - eloss;
eloss = deadlayer.GetEnergyLossTotal(nucleus.GetZ(), nucleus.GetA(), ke, M_PI - thetaIncident);
ke = nucleus.GetKE() - eloss;
//ke -= eloss;
if(ke <= ENERGY_THRESHOLD) break; //deadlayer check
e_deposited = sabre_eloss.GetEnergyLossTotal(nucleus.GetZ(), nucleus.GetA(), ke, M_PI - thetaIncident);
return std::make_pair(true, e_deposited);
}
for(auto& detector : m_detectors)
{
if(!m_activeDetectors[detector.GetDetectorID()])
continue;
auto channel = detector.GetTrajectoryRingWedge(nucleus.vec4.Theta(), nucleus.vec4.Phi());
if(channel.first == -1 || channel.second == -1)
continue;
if(m_deadMap.IsDead(detector.GetDetectorID(), channel.first, 0) || m_deadMap.IsDead(detector.GetDetectorID(), channel.second, 1))
break; //dead channel check
observation.detectFlag = true;
observation.direction = detector.GetTrajectoryCoordinates(nucleus.vec4.Theta(), nucleus.vec4.Phi());
thetaIncident = std::acos(observation.direction.Dot(detector.GetNormTilted())/(observation.direction.R()));
//Energy loss
ke = nucleus.GetKE();
if(m_degradedDetectors[detector.GetDetectorID()])
ke -= m_degraderEloss.GetEnergyLossTotal(nucleus.Z, nucleus.A, ke, M_PI - thetaIncident);
ke -= m_deadlayerEloss.GetEnergyLossTotal(nucleus.Z, nucleus.A, ke, M_PI - thetaIncident);
if(ke <= s_energyThreshold)
break;
observation.det_name = "SABRE"+std::to_string(detector.GetDetectorID());
observation.energy_deposited = m_detectorEloss.GetEnergyLossTotal(nucleus.Z, nucleus.A, ke, M_PI - thetaIncident);
return observation;
}
return std::make_pair(false,0.0);
observation.detectFlag = false;
return observation;
}
void SabreEfficiency::CountCoincidences(const Mask::MaskFileData& data, std::vector<int>& counts, Mask::RxnType rxn_type) {
if (rxn_type == Mask::RxnType::PureDecay && data.detect_flag[1] && data.detect_flag[2])
void SabreEfficiency::CountCoincidences(const std::vector<Mask::Nucleus>& data, std::vector<int>& counts)
{
if (data.size() == 3 && data[1].isDetected && data[2].isDetected)
{
counts[0]++;
}
else if (rxn_type == Mask::RxnType::OneStepRxn && data.detect_flag[2] && data.detect_flag[3])
else if (data.size() == 4 && data[2].isDetected && data[3].isDetected)
{
counts[0]++;
}
else if(rxn_type == Mask::RxnType::TwoStepRxn)
else if(data.size() == 6)
{
if(data.detect_flag[2] && data.detect_flag[4])
if(data[2].isDetected && data[4].isDetected)
{
counts[0]++;
}
if(data.detect_flag[2] && data.detect_flag[5])
if(data[2].isDetected && data[5].isDetected)
{
counts[1]++;
}
if(data.detect_flag[4] && data.detect_flag[5])
if(data[4].isDetected && data[5].isDetected)
{
counts[2]++;
}
if(data.detect_flag[2] && data.detect_flag[4] && data.detect_flag[5])
if(data[2].isDetected && data[4].isDetected && data[5].isDetected)
{
counts[3]++;
}
}
else if(rxn_type == Mask::RxnType::ThreeStepRxn)
else if(data.size() == 8)
{
if(data.detect_flag[2] && data.detect_flag[4])
if(data[2].isDetected && data[4].isDetected)
{
counts[0]++;
}
if(data.detect_flag[2] && data.detect_flag[6])
if(data[2].isDetected && data[6].isDetected)
{
counts[1]++;
}
if(data.detect_flag[2] && data.detect_flag[7])
if(data[2].isDetected && data[7].isDetected)
{
counts[2]++;
}
if(data.detect_flag[4] && data.detect_flag[6])
if(data[4].isDetected && data[6].isDetected)
{
counts[3]++;
}
if(data.detect_flag[4] && data.detect_flag[7])
if(data[4].isDetected && data[7].isDetected)
{
counts[4]++;
}
if(data.detect_flag[6] && data.detect_flag[7])
if(data[6].isDetected && data[7].isDetected)
{
counts[5]++;
}
if(data.detect_flag[2] && data.detect_flag[4] && data.detect_flag[6])
if(data[2].isDetected && data[4].isDetected && data[6].isDetected)
{
counts[6]++;
}
if(data.detect_flag[2] && data.detect_flag[4] && data.detect_flag[7])
if(data[2].isDetected && data[4].isDetected && data[7].isDetected)
{
counts[7]++;
}
if(data.detect_flag[2] && data.detect_flag[6] && data.detect_flag[7])
if(data[2].isDetected && data[6].isDetected && data[7].isDetected)
{
counts[8]++;
}
if(data.detect_flag[4] && data.detect_flag[6] && data.detect_flag[7])
if(data[4].isDetected && data[6].isDetected && data[7].isDetected)
{
counts[9]++;
}
if(data.detect_flag[2] && data.detect_flag[4] && data.detect_flag[6] && data.detect_flag[7])
if(data[2].isDetected && data[4].isDetected && data[6].isDetected && data[7].isDetected)
{
counts[10]++;
}

View File

@ -0,0 +1,51 @@
#ifndef SABREEFFICIENCY_H
#define SABREEFFICIENCY_H
#include "DetectorEfficiency.h"
#include "SabreDetector.h"
#include "Target.h"
#include "SabreDeadChannelMap.h"
#include "Mask/Nucleus.h"
class SabreEfficiency : public DetectorEfficiency
{
public:
SabreEfficiency();
~SabreEfficiency();
void SetDeadChannelMap(const std::string& filename) { m_deadMap.LoadMapfile(filename); };
void CalculateEfficiency(const std::string& inputname, const std::string& outputname, const std::string& statsname) override;
void DrawDetectorSystem(const std::string& filename) override;
double RunConsistencyCheck() override;
private:
DetectorResult IsSabre(Mask::Nucleus& nucleus);
void CountCoincidences(const std::vector<Mask::Nucleus>& data, std::vector<int>& counts);
std::vector<SabreDetector> m_detectors;
Mask::Target m_deadlayerEloss;
Mask::Target m_detectorEloss;
Mask::Target m_degraderEloss;
SabreDeadChannelMap m_deadMap;
bool m_activeDetectors[5];
bool m_degradedDetectors[5];
//Sabre constants
static constexpr double s_innerR = 0.0326;
static constexpr double s_outerR = 0.1351;
static constexpr double s_tilt = 40.0;
static constexpr double s_zOffset = -0.1245;
static constexpr double s_deltaPhi = 54.4; //delta phi for each det
static constexpr int s_nDets = 5;
static constexpr double s_centerPhiList[s_nDets] = {306.0, 18.0, 234.0, 162.0, 90.0};
static constexpr double s_deg2rad = M_PI/180.0;
static constexpr double s_deadlayerThickness = 50 * 1e-7 * 2.3296 * 1e6; // ug/cm^2 (50 nm thick * density)
static constexpr double s_detectorThickness = 500 * 1e-4 * 2.3926 * 1e6; // ug/cm^2 (500 um thick * density)
static constexpr double s_degraderThickness = 70.0 * 1.0e-4 * 16.69 * 1e6; //tantalum degrader (70 um thick)
static constexpr double s_energyThreshold = 0.25; //in MeV
};
#endif

View File

@ -17,32 +17,34 @@
*/
StripDetector::StripDetector(int ns, double len, double wid, double cphi, double cz, double crho) :
m_norm_unrot(1.0,0.0,0.0), m_uniform_fraction(0.0, 1.0), rndmFlag(false)
m_norm(1.0,0.0,0.0), m_uniformFraction(0.0, 1.0), m_isSmearing(false)
{
num_strips = ns;
m_nStrips = ns;
length = std::fabs(len);
total_width = std::fabs(wid);
front_strip_width = total_width/num_strips;
back_strip_length = length/num_strips;
m_stripLength = std::fabs(len);
m_totalWidth = std::fabs(wid);
m_frontStripWidth = m_totalWidth/m_nStrips;
m_backStripLength = m_stripLength/m_nStrips;
while (cphi < 0) cphi += 2*M_PI;
center_phi = cphi;
center_z = cz;
center_rho = std::fabs(crho);
while (cphi < 0)
cphi += 2*M_PI;
m_centerPhi = cphi;
m_centerZ = cz;
m_centerRho = std::fabs(crho);
zRot.SetAngle(center_phi);
m_zRotation.SetAngle(m_centerPhi);
front_strip_coords.resize(num_strips);
back_strip_coords.resize(num_strips);
rotated_front_strip_coords.resize(num_strips);
rotated_back_strip_coords.resize(num_strips);
for(int i=0; i<num_strips; i++) {
front_strip_coords[i].resize(num_corners);
back_strip_coords[i].resize(num_corners);
rotated_front_strip_coords[i].resize(num_corners);
rotated_back_strip_coords[i].resize(num_corners);
m_frontStripCoords.resize(m_nStrips);
m_backStripCoords.resize(m_nStrips);
m_rotFrontStripCoords.resize(m_nStrips);
m_rotBackStripCoords.resize(m_nStrips);
for(int i=0; i<m_nStrips; i++)
{
m_frontStripCoords[i].resize(s_nCorners);
m_backStripCoords[i].resize(s_nCorners);
m_rotFrontStripCoords[i].resize(s_nCorners);
m_rotBackStripCoords[i].resize(s_nCorners);
}
CalculateCorners();
@ -50,99 +52,107 @@ StripDetector::StripDetector(int ns, double len, double wid, double cphi, double
StripDetector::~StripDetector() {}
void StripDetector::CalculateCorners() {
void StripDetector::CalculateCorners()
{
double y_min, y_max, z_min, z_max;
for (int s=0; s<num_strips; s++) {
y_max = total_width/2.0 - front_strip_width*s;
y_min = total_width/2.0 - front_strip_width*(s+1);
z_max = center_z + length/2.0;
z_min = center_z - length/2.0;
front_strip_coords[s][2] = Mask::Vec3(center_rho, y_max, z_max);
front_strip_coords[s][3] = Mask::Vec3(center_rho, y_max, z_min);
front_strip_coords[s][0] = Mask::Vec3(center_rho, y_min, z_max);
front_strip_coords[s][1] = Mask::Vec3(center_rho, y_min, z_min);
for (int s=0; s<m_nStrips; s++)
{
y_max = m_totalWidth/2.0 - m_frontStripWidth*s;
y_min = m_totalWidth/2.0 - m_frontStripWidth*(s+1);
z_max = m_centerZ + m_stripLength/2.0;
z_min = m_centerZ - m_stripLength/2.0;
m_frontStripCoords[s][2].SetXYZ(m_centerRho, y_max, z_max);
m_frontStripCoords[s][3].SetXYZ(m_centerRho, y_max, z_min);
m_frontStripCoords[s][0].SetXYZ(m_centerRho, y_min, z_max);
m_frontStripCoords[s][1].SetXYZ(m_centerRho, y_min, z_min);
z_max = (center_z - length/2.0) + (s+1)*back_strip_length;
z_min = (center_z - length/2.0) + (s)*back_strip_length;
y_max = total_width/2.0;
y_min = -total_width/2.0;
back_strip_coords[s][2] = Mask::Vec3(center_rho, y_max, z_max);
back_strip_coords[s][3] = Mask::Vec3(center_rho, y_max, z_min);
back_strip_coords[s][0] = Mask::Vec3(center_rho, y_min, z_max);
back_strip_coords[s][1] = Mask::Vec3(center_rho, y_min, z_min);
z_max = (m_centerZ - m_stripLength/2.0) + (s+1)*m_backStripLength;
z_min = (m_centerZ - m_stripLength/2.0) + (s)*m_backStripLength;
y_max = m_totalWidth/2.0;
y_min = -m_totalWidth/2.0;
m_backStripCoords[s][2].SetXYZ(m_centerRho, y_max, z_max);
m_backStripCoords[s][3].SetXYZ(m_centerRho, y_max, z_min);
m_backStripCoords[s][0].SetXYZ(m_centerRho, y_min, z_max);
m_backStripCoords[s][1].SetXYZ(m_centerRho, y_min, z_min);
}
for(int s=0; s<num_strips; s++) {
rotated_front_strip_coords[s][0] = zRot*front_strip_coords[s][0];
rotated_front_strip_coords[s][1] = zRot*front_strip_coords[s][1];
rotated_front_strip_coords[s][2] = zRot*front_strip_coords[s][2];
rotated_front_strip_coords[s][3] = zRot*front_strip_coords[s][3];
for(int s=0; s<m_nStrips; s++)
{
m_rotFrontStripCoords[s][0] = m_zRotation*m_frontStripCoords[s][0];
m_rotFrontStripCoords[s][1] = m_zRotation*m_frontStripCoords[s][1];
m_rotFrontStripCoords[s][2] = m_zRotation*m_frontStripCoords[s][2];
m_rotFrontStripCoords[s][3] = m_zRotation*m_frontStripCoords[s][3];
rotated_back_strip_coords[s][0] = zRot*back_strip_coords[s][0];
rotated_back_strip_coords[s][1] = zRot*back_strip_coords[s][1];
rotated_back_strip_coords[s][2] = zRot*back_strip_coords[s][2];
rotated_back_strip_coords[s][3] = zRot*back_strip_coords[s][3];
m_rotBackStripCoords[s][0] = m_zRotation*m_backStripCoords[s][0];
m_rotBackStripCoords[s][1] = m_zRotation*m_backStripCoords[s][1];
m_rotBackStripCoords[s][2] = m_zRotation*m_backStripCoords[s][2];
m_rotBackStripCoords[s][3] = m_zRotation*m_backStripCoords[s][3];
}
}
Mask::Vec3 StripDetector::GetHitCoordinates(int front_stripch, double front_strip_ratio) {
ROOT::Math::XYZPoint StripDetector::GetHitCoordinates(int front_stripch, double front_strip_ratio)
{
if (!ValidChannel(front_stripch) || !ValidRatio(front_strip_ratio)) return Mask::Vec3(0,0,0);
if (!ValidChannel(front_stripch) || !ValidRatio(front_strip_ratio))
return ROOT::Math::XYZPoint(0,0,0);
double y;
if(rndmFlag) {
y = -total_width/2.0 + (front_stripch + m_uniform_fraction(Mask::RandomGenerator::GetInstance().GetGenerator()))*front_strip_width;
} else {
y = -total_width/2.0 + (front_stripch+0.5)*front_strip_width;
}
if(m_isSmearing)
y = -m_totalWidth/2.0 + (front_stripch + m_uniformFraction(Mask::RandomGenerator::GetInstance().GetGenerator()))*m_frontStripWidth;
else
y = -m_totalWidth/2.0 + (front_stripch+0.5)*m_frontStripWidth;
//recall we're still assuming phi=0 det:
Mask::Vec3 coords(center_rho, y, front_strip_ratio*(length/2) + center_z);
ROOT::Math::XYZPoint coords(m_centerRho, y, front_strip_ratio*(m_stripLength/2) + m_centerZ);
//NOW rotate by appropriate phi
return zRot*coords;
return m_zRotation*coords;
}
StripHit StripDetector::GetChannelRatio(double theta, double phi) {
StripHit StripDetector::GetChannelRatio(double theta, double phi)
{
StripHit hit;
while (phi < 0) phi += 2*M_PI;
while (phi < 0)
phi += 2*M_PI;
//to make the math easier (and the same for each det), rotate the input phi
//BACKWARD by the phi of the det, s.t. we are looking along x-axis
phi -= center_phi;
phi -= m_centerPhi;
if (phi > M_PI) phi -= 2*M_PI;
if (phi > M_PI)
phi -= 2*M_PI;
//then we can check easily whether it even hit the detector in phi
double det_max_phi = atan2(total_width/2,center_rho);
double det_max_phi = std::atan2(m_totalWidth/2,m_centerRho);
double det_min_phi = -det_max_phi;
if (phi < det_min_phi || phi > det_max_phi) return hit;
if (phi < det_min_phi || phi > det_max_phi)
return hit;
//for theta it's not so simple, so we have to go through the typical plane-intersect method
//first thing's first: we have a fixed x for the entire detector plane:
double xhit = center_rho;
double xhit = m_centerRho;
//thus we find the corresponding y and z for that fixed x, given the input theta and phi:
double yhit = xhit*tan(phi);
double zhit = sqrt(xhit*xhit+yhit*yhit)/tan(theta);
for (int s=0; s<num_strips; s++) {
if (xhit >= front_strip_coords[s][0].GetX() && xhit <= front_strip_coords[s][0].GetX() && //Check min and max x (constant in flat)
yhit >= front_strip_coords[s][1].GetY() && yhit <= front_strip_coords[s][2].GetY() && //Check min and max y
zhit >= front_strip_coords[s][1].GetZ() && zhit <= front_strip_coords[s][0].GetZ()) //Check min and max z
for (int s=0; s<m_nStrips; s++) {
if (xhit >=m_frontStripCoords[s][0].X() && xhit <=m_frontStripCoords[s][0].X() && //Check min and max x (constant in flat)
yhit >=m_frontStripCoords[s][1].Y() && yhit <=m_frontStripCoords[s][2].Y() && //Check min and max y
zhit >=m_frontStripCoords[s][1].Z() && zhit <=m_frontStripCoords[s][0].Z()) //Check min and max z
{
hit.front_strip_index = s;
hit.front_ratio = (zhit-center_z)/(length/2);
hit.front_ratio = (zhit-m_centerZ)/(m_stripLength/2);
break;
}
}
for (int s=0; s<num_strips; s++) {
if (xhit >= back_strip_coords[s][0].GetX() && xhit <= back_strip_coords[s][0].GetX() && //Check min and max x (constant in flat)
yhit >= back_strip_coords[s][1].GetY() && yhit <= back_strip_coords[s][2].GetY() && //Check min and max y
zhit >= back_strip_coords[s][1].GetZ() && zhit <= back_strip_coords[s][0].GetZ()) //Check min and max z
for (int s=0; s<m_nStrips; s++) {
if (xhit >= m_backStripCoords[s][0].X() && xhit <= m_backStripCoords[s][0].X() && //Check min and max x (constant in flat)
yhit >= m_backStripCoords[s][1].Y() && yhit <= m_backStripCoords[s][2].Y() && //Check min and max y
zhit >= m_backStripCoords[s][1].Z() && zhit <= m_backStripCoords[s][0].Z()) //Check min and max z
{
hit.back_strip_index = s;
break;

View File

@ -0,0 +1,82 @@
#ifndef STRIP_DETECTOR_H
#define STRIP_DETECTOR_H
// +z is along beam axis
// +y is vertically "downward" in the lab frame
//angles must be in radians, but distances can be whatever
//PROVIDED all input distances are the same
//Front strips from largest y to smallest y
//Back strips from lowest z to highest z
#include <cmath>
#include <vector>
#include "Math/Point3D.h"
#include "Math/Vector3D.h"
#include "Math/RotationZ.h"
#include "Mask/RandomGenerator.h"
struct StripHit
{
int front_strip_index=-1;
int back_strip_index=-1;
double front_ratio=0.0;
};
class StripDetector
{
public:
StripDetector(int ns, double len, double wid, double cphi, double cz, double crho);
~StripDetector();
const ROOT::Math::XYZPoint& GetFrontStripCoordinates(int stripch, int corner) const { return m_frontStripCoords[stripch][corner]; }
const ROOT::Math::XYZPoint& GetBackStripCoordinates(int stripch, int corner) const { return m_backStripCoords[stripch][corner]; }
const ROOT::Math::XYZPoint& GetRotatedFrontStripCoordinates(int stripch, int corner) const
{
return m_rotFrontStripCoords[stripch][corner];
}
const ROOT::Math::XYZPoint& GetRotatedBackStripCoordinates(int stripch, int corner) const
{
return m_rotBackStripCoords[stripch][corner];
}
ROOT::Math::XYZVector GetNormRotated() const { return m_zRotation * m_norm; }
void SetPixelSmearing(bool isSmearing) { m_isSmearing = isSmearing; }
ROOT::Math::XYZPoint GetHitCoordinates(int front_stripch, double front_strip_ratio);
StripHit GetChannelRatio(double theta, double phi);
private:
bool ValidChannel(int f) { return ((f >= 0 && f < m_nStrips) ? true : false); };
bool ValidRatio(double r) { return ((r >= -1 && r <= 1) ? true : false); };
void CalculateCorners();
int m_nStrips;
static constexpr int s_nCorners = 4;
double m_stripLength; //common to all strips, hence total
double m_totalWidth;
double m_frontStripWidth; //assuming equal widths
double m_backStripLength; //assuming equal widths
double m_centerPhi; //assuming det centered above x-axis (corresponds to zero phi)
double m_centerZ;
double m_centerRho; //perpendicular radius from axis
std::vector<std::vector<ROOT::Math::XYZPoint>> m_frontStripCoords, m_backStripCoords;
std::vector<std::vector<ROOT::Math::XYZPoint>> m_rotFrontStripCoords, m_rotBackStripCoords;
ROOT::Math::XYZVector m_norm;
ROOT::Math::RotationZ m_zRotation;
std::uniform_real_distribution<double> m_uniformFraction;
bool m_isSmearing;
};
#endif

View File

@ -4,9 +4,11 @@
#include <iostream>
#include <string>
int main(int argc, char** argv) {
int main(int argc, char** argv)
{
if(argc != 4) {
if(argc != 4)
{
std::cerr<<"Incorrect number of commandline arguments! Returning."<<std::endl;
return 1;
}
@ -25,18 +27,12 @@ int main(int argc, char** argv) {
/*
try {
AnasenEfficiency anasen;
std::string mapfile = "./etc/AnasenDeadChannels.txt";
anasen.SetDeadChannelMap(mapfile);
anasen.CalculateEfficiency(inputname, outputname, statsname);
AnasenEfficiency anasen;
std::string mapfile = "./etc/AnasenDeadChannels.txt";
anasen.SetDeadChannelMap(mapfile);
anasen.CalculateEfficiency(inputname, outputname, statsname);
//std::cout<<"Running consistency check(1=success): "<<anasen.RunConsistencyCheck()<<std::endl;
//anasen.DrawDetectorSystem("/data1/gwm17/TRIUMF_7Bed/simulation/ANASENGeo_centered_target_targetGap_BackQQQ_fixedZ.txt");
} catch(const std::exception& e) {
std::cerr<<"Error: "<<e.what()<<std::endl;
std::cerr<<"Terminating."<<std::endl;
return 1;
}
*/
return 0;
}

View File

@ -8,26 +8,28 @@
namespace Mask {
AngularDistribution::AngularDistribution() :
uniform_cosine_dist(-1.0, 1.0), uniform_prob_dist(0.0, 1.0), branchingRatio(1.0), L(0), isoFlag(true)
m_uniformCosineDist(-1.0, 1.0), m_uniformProbDist(0.0, 1.0), m_branchingRatio(1.0), m_L(0), m_isIsotropic(true)
{
}
AngularDistribution::AngularDistribution(const std::string& file) :
branchingRatio(1.0), L(0), isoFlag(true)
m_branchingRatio(1.0), m_L(0), m_isIsotropic(true)
{
ReadDistributionFile(file);
}
AngularDistribution::~AngularDistribution() {}
void AngularDistribution::ReadDistributionFile(const std::string& file) {
void AngularDistribution::ReadDistributionFile(const std::string& file)
{
if(file == "none" || file == "") {
L=0;
branchingRatio=1.0;
constants.clear();
constants.push_back(0.5);
isoFlag = true;
if(file == "none" || file == "")
{
m_L=0;
m_branchingRatio=1.0;
m_constants.clear();
m_constants.push_back(0.5);
m_isIsotropic = true;
return;
}
@ -36,67 +38,79 @@ namespace Mask {
int l;
double par;
if(!input.is_open()) {
if(!input.is_open())
{
std::cerr<<"Unable to open distribution file. All values reset to default."<<std::endl;
L=0;
branchingRatio=1.0;
constants.clear();
constants.push_back(0.5);
isoFlag = true;
m_L=0;
m_branchingRatio=1.0;
m_constants.clear();
m_constants.push_back(0.5);
m_isIsotropic = true;
return;
}
input>>junk>>l;
while(input>>junk) {
while(input>>junk)
{
input>>par;
constants.push_back(par);
m_constants.push_back(par);
}
input.close();
if(constants.size() != ((unsigned int) l+1)) {
std::cerr<<"Unexpected number of constants for given angular momentum! Expected "<<l+1<<" and given "<<constants.size()<<std::endl;
if(m_constants.size() != ((std::size_t) l+1))
{
std::cerr<<"Unexpected number of constants for given angular momentum! Expected "<<l+1<<" and given "<<m_constants.size()<<std::endl;
std::cerr<<"Setting all values to default."<<std::endl;
branchingRatio=1.0;
constants.clear();
constants.push_back(0.5);
isoFlag = true;
m_L=0;
m_branchingRatio=1.0;
m_constants.clear();
m_constants.push_back(0.5);
m_isIsotropic = true;
return;
}
//Total branching ratio
branchingRatio = constants[0]*2.0;
L = l;
m_branchingRatio = m_constants[0]*2.0;
m_L = l;
std::cout<<"Angular distribution from "<<file<<" branching ratio: "<<m_branchingRatio<<std::endl;
std::cout<<"Angular distribution from "<<file<<" L: "<<m_L<<std::endl;
//Renormalize distribution such that total prob is 1.0.
//Test branching ratio to see if we "make" a decay particle,
//then use re-normalized distribution to pick an angle.
if(constants[0] < 0.5) {
double norm = 0.5/constants[0];
for(auto& value : constants)
if(m_constants[0] < 0.5)
{
double norm = 0.5/m_constants[0];
for(auto& value : m_constants)
value *= norm;
}
isoFlag = false;
m_isIsotropic = false;
}
double AngularDistribution::GetRandomCosTheta() {
if(isoFlag)
return uniform_cosine_dist(RandomGenerator::GetInstance().GetGenerator());
double AngularDistribution::GetRandomCosTheta()
{
if(m_isIsotropic)
return m_uniformCosineDist(RandomGenerator::GetInstance().GetGenerator());
double test, probability;
double costheta;
test = uniform_prob_dist(RandomGenerator::GetInstance().GetGenerator());
if(test > branchingRatio) return -10;
test = m_uniformProbDist(RandomGenerator::GetInstance().GetGenerator());
if(test > m_branchingRatio)
return -10;
do {
do
{
probability = 0.0;
costheta = uniform_cosine_dist(RandomGenerator::GetInstance().GetGenerator());
test = uniform_prob_dist(RandomGenerator::GetInstance().GetGenerator());
for(unsigned int i=0; i<constants.size(); i++)
probability += constants[i]*P_l(i*2, costheta);
} while(test > probability);
costheta = m_uniformCosineDist(RandomGenerator::GetInstance().GetGenerator());
test = m_uniformProbDist(RandomGenerator::GetInstance().GetGenerator());
for(std::size_t i=0; i<m_constants.size(); i++)
probability += m_constants[i]*P_l(i*2, costheta);
}
while(test > probability);
return costheta;
}

View File

@ -0,0 +1,35 @@
#ifndef ANGULARDISTRIBUTION_H
#define ANGULARDISTRIBUTION_H
#include <string>
#include <vector>
#include <random>
namespace Mask {
class AngularDistribution
{
public:
AngularDistribution();
AngularDistribution(const std::string& file);
~AngularDistribution();
void ReadDistributionFile(const std::string& file);
double GetRandomCosTheta();
int GetL() { return m_L; }
double GetBranchingRatio() { return m_branchingRatio; }
private:
bool IsIsotropic() { return m_isIsotropic; }
std::uniform_real_distribution<double> m_uniformCosineDist;
std::uniform_real_distribution<double> m_uniformProbDist;
double m_branchingRatio;
int m_L;
std::vector<double> m_constants;
bool m_isIsotropic;
};
}
#endif

View File

@ -1,30 +1,56 @@
add_library(MaskDict SHARED)
target_include_directories(MaskDict
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}
SYSTEM PUBLIC ${ROOT_INCLUDE_DIRS}
)
ROOT_GENERATE_DICTIONARY(mask_dict Nucleus.h LINKDEF LinkDef_Nucleus.h MODULE MaskDict)
target_sources(MaskDict PRIVATE Nucleus.h Nucleus.cpp MassLookup.h MassLookup.cpp)
target_link_libraries(MaskDict ${ROOT_LIBRARIES})
set_target_properties(MaskDict PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${MASK_LIBRARY_DIR})
add_custom_command(TARGET MaskDict POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
${CMAKE_CURRENT_BINARY_DIR}/libMaskDict_rdict.pcm
${MASK_LIBRARY_DIR}/libMaskDict_rdict.pcm
)
add_library(Mask STATIC)
target_include_directories(Mask
PUBLIC ${MASK_INCLUDE_DIR}
${ROOT_INCLUDE_DIRS}
)
target_sources(Mask PRIVATE
AngularDistribution.cpp
AngularDistribution.h
DecaySystem.cpp
EnergyLoss.cpp
DecaySystem.h
LayeredTarget.cpp
LayeredTarget.h
LegendrePoly.cpp
LegendrePoly.h
MaskApp.cpp
MaskFile.cpp
MaskApp.h
MassLookup.cpp
Nucleus.cpp
MassLookup.h
OneStepSystem.cpp
OneStepSystem.h
RandomGenerator.cpp
RandomGenerator.h
Reaction.cpp
Reaction.h
ReactionSystem.cpp
Rotation.cpp
ReactionSystem.h
Stopwatch.cpp
Stopwatch.h
Target.cpp
Target.h
ThreeStepSystem.cpp
ThreeStepSystem.h
TwoStepSystem.cpp
Vec3.cpp
Vec4.cpp
TwoStepSystem.h
)
target_link_libraries(Mask catima)
set_target_properties(Mask PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${MASK_LIBRARY_DIR})
target_link_libraries(Mask catima MaskDict ${ROOT_LIBRARIES})
set_target_properties(Mask PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${MASK_LIBRARY_DIR})

View File

@ -1,76 +1,81 @@
#include "DecaySystem.h"
#include "RandomGenerator.h"
#include <sstream>
namespace Mask {
DecaySystem::DecaySystem() :
ReactionSystem()
{
nuclei.resize(3);
m_nuclei.resize(3);
}
DecaySystem::DecaySystem(std::vector<int>& z, std::vector<int>& a) :
DecaySystem::DecaySystem(const std::vector<int>& z, const std::vector<int>& a) :
ReactionSystem()
{
nuclei.resize(3);
m_nuclei.resize(3);
SetNuclei(z, a);
}
DecaySystem::~DecaySystem() {}
bool DecaySystem::SetNuclei(std::vector<int>& z, std::vector<int>& a) {
if(z.size() != a.size() || z.size() != 2) {
bool DecaySystem::SetNuclei(const std::vector<int>& z, const std::vector<int>& a)
{
if(z.size() != a.size() || z.size() != 2)
return false;
}
step1.SetNuclei(z[0], a[0], 0, 0, z[1], a[1]);
int zr = z[0] - z[1];
int ar = a[0] - a[1];
m_nuclei[0] = CreateNucleus(z[0], a[0]); //target
m_nuclei[1] = CreateNucleus(z[1], a[1]); //breakup1
m_nuclei[2] = CreateNucleus(zr, ar); //breakup2
m_step1.BindNuclei(&(m_nuclei[0]), nullptr, &(m_nuclei[1]), &(m_nuclei[2]));
SetSystemEquation();
return true;
}
const std::vector<Nucleus>& DecaySystem::GetNuclei()
std::vector<Nucleus>* DecaySystem::GetNuclei()
{
nuclei[0] = step1.GetTarget();
nuclei[1] = step1.GetEjectile();
nuclei[2] = step1.GetResidual();
return nuclei;
return &m_nuclei;
}
void DecaySystem::LinkTarget() {
step1.SetLayeredTarget(&target);
m_step1.SetLayeredTarget(&m_target);
rxnLayer = target.FindLayerContaining(step1.GetTarget().GetZ(), step1.GetTarget().GetA());
if(rxnLayer != -1) {
step1.SetRxnLayer(rxnLayer);
target_set_flag = true;
} else {
m_rxnLayer = m_target.FindLayerContaining(m_nuclei[0].Z, m_nuclei[0].A);
if(m_rxnLayer != m_target.GetNumberOfLayers())
{
m_step1.SetRxnLayer(m_rxnLayer);
m_isTargetSet = true;
}
else
throw ReactionLayerException();
}
}
void DecaySystem::SetSystemEquation() {
m_sys_equation = step1.GetTarget().GetIsotopicSymbol();
m_sys_equation += "-> ";
m_sys_equation += step1.GetEjectile().GetIsotopicSymbol();
m_sys_equation += "+";
m_sys_equation += step1.GetResidual().GetIsotopicSymbol();
void DecaySystem::SetSystemEquation()
{
std::stringstream stream;
stream << m_nuclei[0].isotopicSymbol << "->"
<< m_nuclei[1].isotopicSymbol << "+"
<< m_nuclei[2].isotopicSymbol;
m_sysEquation = stream.str();
}
void DecaySystem::RunSystem() {
void DecaySystem::RunSystem()
{
//Link up the target if it hasn't been done yet
if(!target_set_flag) {
if(!m_isTargetSet)
LinkTarget();
}
double rxnTheta = std::acos(decay1dist.GetRandomCosTheta());
double rxnTheta = std::acos(m_step1Distribution.GetRandomCosTheta());
double rxnPhi = (*m_phi1Range)(RandomGenerator::GetInstance().GetGenerator());
step1.SetPolarRxnAngle(rxnTheta);
step1.SetAzimRxnAngle(rxnPhi);
step1.TurnOnResidualEloss();
step1.Calculate();
m_step1.SetPolarRxnAngle(rxnTheta);
m_step1.SetAzimRxnAngle(rxnPhi);
m_step1.SetResidualEnergyLoss(true);
m_step1.Calculate();
}
}

36
src/Mask/DecaySystem.h Normal file
View File

@ -0,0 +1,36 @@
#ifndef DECAYSYSTEM_H
#define DECAYSYSTEM_H
#include "ReactionSystem.h"
#include "AngularDistribution.h"
namespace Mask {
class DecaySystem: public ReactionSystem {
public:
DecaySystem();
DecaySystem(const std::vector<int>& z, const std::vector<int>& a);
~DecaySystem();
bool SetNuclei(const std::vector<int>& z, const std::vector<int>& a) override;
void RunSystem() override;
std::vector<Nucleus>*GetNuclei() override;
virtual void SetDecay1Distribution(const std::string& filename) override { m_step1Distribution.ReadDistributionFile(filename); }
int GetDecay1AngularMomentum() { return m_step1Distribution.GetL(); }
double GetDecay1BranchingRatio() { return m_step1Distribution.GetBranchingRatio(); }
private:
void LinkTarget() override;
void SetSystemEquation() override;
Reaction m_step1;
AngularDistribution m_step1Distribution;
};
}
#endif

View File

@ -1,243 +0,0 @@
/*
EnergyLoss.cpp
Code for calculating the energy loss of a charged, massive particle through an arbitrary medium.
Based on code written by D.W. Visser at Yale for the original SPANC. Uses energy loss calulations
described by Ziegler in various SRIM textbooks.
Written by G.W. McCann Aug. 2020
*/
#include "Eloss_Tables.h"
#include "EnergyLoss.h"
#include "KinematicsExceptions.h"
#include <iostream>
namespace Mask {
EnergyLoss::EnergyLoss() :
ZP(-1), AP(-1), MP(-1.0), comp_denom(0)
{
}
EnergyLoss::~EnergyLoss() {}
/*Targets are defined by their atomic number, total number of nucleons, and their stoichiometry within the target compound*/
void EnergyLoss::SetTargetComponents(const std::vector<int>& Zt, const std::vector<int>& At, const std::vector<int>& Stoich) {
comp_denom = 0;
ZT = Zt;
AT = At;
for(unsigned int i=0; i<Stoich.size(); i++) {
comp_denom += Stoich[i];
if(ZT[i] > MAX_Z)
throw ELossException("Maximum allowed target Z exceeded");
}
targ_composition.resize(Stoich.size());
for(unsigned int i=0; i<Stoich.size(); i++)
targ_composition[i] = Stoich[i]/comp_denom;
}
/*
Returns units of MeV; thickness in ug/cm^2; e_initial in units of MeV
Energy loss going through the target
*/
double EnergyLoss::GetEnergyLoss(int zp, int ap, double e_initial, double thickness) {
if( ZP != zp) {
ZP = zp;
AP = ap;
MP = MassLookup::GetInstance().FindMass(ZP, AP)*MEV2U;
}
if(thickness == 0.0 || e_initial == 0.0 || zp == 0)
return 0;
double e_final = e_initial;
double x_traversed = 0;
double x_step = 0.25*thickness; //initial step in x
double e_step = GetTotalStoppingPower(e_final)*x_step/1000.0; //initial step in e
double e_threshold = 0.05*e_initial;
int depth=0;
bool go = true;
while(go) {
//If intial guess of step size is too large, shrink until in range
if(e_step/e_final > MAX_FRACTIONAL_STEP && depth < MAX_DEPTH) {
depth++;
x_step *= 0.5;
e_step = GetTotalStoppingPower(e_final)*x_step/1000.0;
} else if((x_step + x_traversed) >= thickness) { //last chunk
go = false;
x_step = thickness - x_traversed; //get valid portion of last chunk
e_final -= GetTotalStoppingPower(e_final)*x_step/1000.0;
if(e_final <= e_threshold)
return e_initial;
} else if(depth == MAX_DEPTH) {
return e_initial;
} else {
x_traversed += x_step;
e_step = GetTotalStoppingPower(e_final)*x_step/1000.0;
e_final -= e_step;
if(e_final <= e_threshold)
return e_initial;
}
}
return e_initial - e_final;
}
/*
Returns units of MeV; thickness in ug/cm^2; e_final in units of MeV
Energy loss going through the target using energy of particle after traversal
*/
double EnergyLoss::GetReverseEnergyLoss(int zp, int ap, double e_final, double thickness) {
if( ZP != zp) {
ZP = zp;
AP = ap;
MP = MassLookup::GetInstance().FindMass(ZP, AP)*MEV2U;
}
double e_initial = e_final;
double x_traversed = 0.0;
double x_step = 0.25*thickness; //initial step in x
double e_step = GetTotalStoppingPower(e_initial)*x_step/1000.0; //initial step in E
bool go = true;
while(go) {
if(e_step/e_initial > MAX_FRACTIONAL_STEP) {
x_step *= 0.5;
e_step = GetTotalStoppingPower(e_initial)*x_step/1000.0;
} else if (x_traversed+x_step > thickness) {
go = false;
x_step = thickness - x_traversed;
e_initial += GetTotalStoppingPower(e_initial)*x_step/1000.0;
} else {
x_traversed += x_step;
e_step = GetTotalStoppingPower(e_initial)*x_step/1000.0;
e_initial += e_step;
}
}
return e_initial-e_final;
}
/*
Returns units of keV/(ug/cm^2)
Calculates Electronic stopping power by first calculating SE for hydrogen through the target and then using
corrections to calculate SE for projectile of interest
*/
double EnergyLoss::GetElectronicStoppingPower(double energy) {
//Wants in units of keV
energy *= 1000.0;
double e_per_u = energy/MP;
std::vector<double> values;
if(e_per_u > MAX_H_E_PER_U) {
throw ELossException("Exceeded maximum allowed energy per nucleon");
} else if (e_per_u > 1000.0) {
for(auto& z: ZT)
values.push_back(Hydrogen_dEdx_High(e_per_u, energy, z));
} else if (e_per_u > 10.0) {
for(auto& z: ZT)
values.push_back(Hydrogen_dEdx_Med(e_per_u, z));
} else if (e_per_u > 0.0) {
for(auto& z: ZT)
values.push_back(Hydrogen_dEdx_Low(e_per_u, z));
} else {
throw ELossException("Negative energy per nucleon; given energy: "+std::to_string(energy));
}
if(values.size() == 0)
throw ELossException("Size of value array is 0. Unable to iterate over target components");
if(ZP > 1) { //not hydrogen, need to account for effective charge
for(unsigned int i=0; i<values.size(); i++)
values[i] *= CalculateEffectiveChargeRatio(e_per_u, ZT[i]);
}
double stopping_total = 0;
double conversion_factor = 0;
for(unsigned int i=0; i<ZT.size(); i++) {
conversion_factor += targ_composition[i]*NATURAL_MASS[ZT[i]];
stopping_total += values[i]*targ_composition[i];
}
stopping_total *= AVOGADRO/conversion_factor;
return stopping_total;
}
//Returns units of keV/(ug/cm^2)
double EnergyLoss::GetNuclearStoppingPower(double energy) {
energy *= 1000.0;
double stopping_total = 0.0;
double sn, x, epsilon, conversion_factor;
for(unsigned int i=0; i<ZT.size(); i++) {
x = (MP + NATURAL_MASS[ZT[i]]) * std::sqrt(std::pow(ZP, 2.0/3.0) + std::pow(ZT[i], 2.0/3.0));
epsilon = 32.53*NATURAL_MASS[ZT[i]]*energy/(ZP*ZT[i]*x);
sn = 8.462*(0.5*std::log(1.0+epsilon)/(epsilon+0.10718*std::pow(epsilon, 0.37544)))*ZP*ZT[i]*MP/x;
conversion_factor = AVOGADRO/NATURAL_MASS[ZT[i]];
stopping_total += sn*conversion_factor*targ_composition[i];
}
return stopping_total;
}
/*Wrapper function for aquiring total stopping (elec + nuc)*/
double EnergyLoss::GetTotalStoppingPower(double energy) {
if(ZP == 0)
return GetNuclearStoppingPower(energy);
return GetElectronicStoppingPower(energy)+GetNuclearStoppingPower(energy);
}
/*Charge rel to H*/
double EnergyLoss::CalculateEffectiveChargeRatio(double e_per_u, int z) {
double z_ratio;
if(ZP == 2) {
double ln_epu = std::log(e_per_u);
double gamma = 1.0+(0.007+0.00005*z)*std::exp(-std::pow(7.6-ln_epu,2.0));
double alpha = 0.7446 + 0.1429*ln_epu + 0.01562*std::pow(ln_epu, 2.0) - 0.00267*std::pow(ln_epu,3.0)
+ 1.338E-6*std::pow(ln_epu,8.0);
z_ratio = gamma*(1.0-std::exp(-alpha))*2.0;
} else if (ZP == 3) {
double ln_epu = std::log(e_per_u);
double gamma = 1.0+(0.007+0.00005*z)*std::exp(-std::pow(7.6-ln_epu,2.0));
double alpha = 0.7138+0.002797*e_per_u+1.348E-6*std::pow(e_per_u, 2.0);
z_ratio = gamma*(1-std::exp(-alpha))*3.0;
} else {
double B = 0.886*std::pow(e_per_u/25.0, 0.5)/std::pow(ZP, 2.0/3.0);
double A = B + 0.0378*std::sin(M_PI/2.0*B);
z_ratio = (1.0 - std::exp(-A)*(1.034-0.1777*std::exp(-0.08114*ZP)))*ZP;
}
return z_ratio*z_ratio; //for stopping power uses ratio sq.
}
double EnergyLoss::Hydrogen_dEdx_Low(double e_per_u, int z) {
return std::sqrt(e_per_u)*HYDROGEN_COEFF[z][0];
}
double EnergyLoss::Hydrogen_dEdx_Med(double e_per_u, int z) {
double x = HYDROGEN_COEFF[z][1]*std::pow(e_per_u, 0.45);
double y = HYDROGEN_COEFF[z][2]/e_per_u * std::log(1.0+HYDROGEN_COEFF[z][3]/e_per_u+HYDROGEN_COEFF[z][4]*e_per_u);
return x*y/(x+y);
}
double EnergyLoss::Hydrogen_dEdx_High(double e_per_u, double energy, int z) {
energy /= 1000.0; //back to MeV for ease of beta calc
double beta_sq = energy * (energy+2.0*MP/MEV2U)/std::pow(energy+MP/MEV2U, 2.0);
double alpha = HYDROGEN_COEFF[z][5]/beta_sq;
double epsilon = HYDROGEN_COEFF[z][6]*beta_sq/(1.0-beta_sq) - beta_sq - HYDROGEN_COEFF[z][7];
for(int i=1; i<5; i++)
epsilon += HYDROGEN_COEFF[z][7+i]*std::pow(std::log(e_per_u), i);
return alpha * std::log(epsilon);
}
//unimplemented
double EnergyLoss::GetRange(double energy) {
std::cerr<<"EnergyLoss::GetRange is not implemented! Returning 0.0"<<std::endl;
return 0.0;
}
}

View File

@ -16,17 +16,16 @@ Written by G.W. McCann Aug. 2020
namespace Mask {
LayeredTarget::LayeredTarget() :
name(""), m_fractional_depth_dist(0.0, 1.0)
m_name(""), m_fractionalDepthDistribution(0.0, 1.0)
{
}
LayeredTarget::~LayeredTarget() {}
/*Add in a Target made of a compound defined by a set of Zs, As, Ss, and a thickness*/
void LayeredTarget::AddLayer(std::vector<int>& Z, std::vector<int>& A, std::vector<int>& stoich, double thickness) {
Target t(thickness);
t.SetElements(Z, A, stoich);
layers.push_back(t);
void LayeredTarget::AddLayer(const std::vector<int>& Z, const std::vector<int>& A, const std::vector<int>& stoich, double thickness)
{
m_layers.emplace_back(Z, A, stoich, thickness);
}
/*
@ -34,9 +33,10 @@ namespace Mask {
Calculates energy loss assuming that the reaction occurs in the middle of the target layer
Note that the layer order can matter!
*/
double LayeredTarget::GetProjectileEnergyLoss(int zp, int ap, double startEnergy, int rxnLayer, double angle) {
if(rxnLayer < 0 || ((unsigned int) rxnLayer) > layers.size()) {
double LayeredTarget::GetProjectileEnergyLoss(int zp, int ap, double startEnergy, std::size_t rxnLayer, double angle)
{
if(rxnLayer > m_layers.size())
{
std::cerr<<"Reaction layer in eloss calculation is not in range! Returning 0"<<std::endl;
return 0.0;
}
@ -44,13 +44,17 @@ namespace Mask {
double eloss = 0.0;
double newEnergy = startEnergy;
double frac;
for(int i=0; i<=rxnLayer; i++) {
if(i == rxnLayer) {
frac = m_fractional_depth_dist(RandomGenerator::GetInstance().GetGenerator());
eloss += layers[i].GetEnergyLossFractionalDepth(zp, ap, newEnergy, angle, frac);
for(std::size_t i=0; i<=rxnLayer; i++)
{
if(i == rxnLayer)
{
frac = m_fractionalDepthDistribution(RandomGenerator::GetInstance().GetGenerator());
eloss += m_layers[i].GetEnergyLossFractionalDepth(zp, ap, newEnergy, angle, frac);
newEnergy = startEnergy - eloss;
} else {
eloss += layers[i].GetEnergyLossTotal(zp, ap, newEnergy, angle);
}
else
{
eloss += m_layers[i].GetEnergyLossTotal(zp, ap, newEnergy, angle);
newEnergy = startEnergy-eloss;
}
}
@ -63,83 +67,96 @@ namespace Mask {
Calculates energy loss assuming that the reaction occurs in the middle of the target
Note that the layer order can matter!
*/
double LayeredTarget::GetEjectileEnergyLoss(int ze, int ae, double startEnergy, int rxnLayer, double angle) {
double LayeredTarget::GetEjectileEnergyLoss(int ze, int ae, double startEnergy, std::size_t rxnLayer, double angle) {
if(rxnLayer < 0 || ((unsigned int) rxnLayer) > layers.size()) {
if(rxnLayer > m_layers.size())
{
std::cerr<<"Reaction layer in eloss calculation is not in range! Returning 0"<<std::endl;
return 0.0;
}
double eloss = 0.0;
if(angle < M_PI/2.0) {
RandomGenerator& gen = RandomGenerator::GetInstance();
if(angle < M_PI/2.0)
{
double newEnergy = startEnergy;
for(unsigned int i=rxnLayer; i<layers.size(); i++) {
if(i == ((unsigned int)rxnLayer)) {
eloss += layers[i].GetEnergyLossFractionalDepth(ze, ae, newEnergy, angle, m_fractional_depth_dist(RandomGenerator::GetInstance().GetGenerator()));
newEnergy = startEnergy - eloss;
} else {
eloss += layers[i].GetEnergyLossTotal(ze, ae, newEnergy, angle);
newEnergy = startEnergy - eloss;
}
eloss += m_layers[rxnLayer].GetEnergyLossFractionalDepth(ze, ae, newEnergy, angle, m_fractionalDepthDistribution(gen.GetGenerator()));
newEnergy = startEnergy - eloss;
if(rxnLayer == m_layers.size())
return eloss;
for(std::size_t i=rxnLayer; i<m_layers.size(); i++)
{
eloss += m_layers[i].GetEnergyLossTotal(ze, ae, newEnergy, angle);
newEnergy = startEnergy - eloss;
}
} else { //Travelling backwards through target
}
else
{ //Travelling backwards through target
double newEnergy = startEnergy;
for(int i=rxnLayer; i>=0; i--) {
if(i == ((unsigned int)rxnLayer)) {
eloss += layers[i].GetEnergyLossFractionalDepth(ze, ae, newEnergy, angle, m_fractional_depth_dist(RandomGenerator::GetInstance().GetGenerator()));
newEnergy = startEnergy - eloss;
} else {
eloss += layers[i].GetEnergyLossTotal(ze, ae, newEnergy, angle);
newEnergy = startEnergy - eloss;
}
eloss += m_layers[rxnLayer].GetEnergyLossFractionalDepth(ze, ae, newEnergy, angle, m_fractionalDepthDistribution(gen.GetGenerator()));
newEnergy = startEnergy - eloss;
if(rxnLayer == 0)
return eloss;
for(std::size_t i=rxnLayer-1; i>0; i--) //unsigned ints cant be less than 0
{
eloss += m_layers[i].GetEnergyLossTotal(ze, ae, newEnergy, angle);
newEnergy = startEnergy - eloss;
}
eloss += m_layers[0].GetEnergyLossTotal(ze, ae, newEnergy, angle);
newEnergy = startEnergy - eloss;
}
return eloss;
}
/*ReverseEnergyLoss version of GetEjectileEnergyLoss*/
double LayeredTarget::GetEjectileReverseEnergyLoss(int ze, int ae, double startEnergy, int rxnLayer, double angle) {
if(rxnLayer < 0 || ((unsigned int) rxnLayer) > layers.size()) {
double LayeredTarget::GetEjectileReverseEnergyLoss(int ze, int ae, double startEnergy, std::size_t rxnLayer, double angle)
{
if(rxnLayer > m_layers.size())
{
std::cerr<<"Reaction layer in eloss calculation is not in range! Returning 0"<<std::endl;
return 0.0;
}
double eloss = 0.0;
if(angle < M_PI/2.0) {
RandomGenerator& gen = RandomGenerator::GetInstance();
if(angle < M_PI/2.0)
{
double newEnergy = startEnergy;
for(int i=(layers.size()-1); i>=rxnLayer; i--) {
if(i == rxnLayer) {
eloss += layers[i].GetReverseEnergyLossFractionalDepth(ze, ae, newEnergy, angle, m_fractional_depth_dist(RandomGenerator::GetInstance().GetGenerator()));
newEnergy = startEnergy + eloss;
} else {
eloss += layers[i].GetReverseEnergyLossTotal(ze, ae, newEnergy, angle);
newEnergy = startEnergy + eloss;
}
for(std::size_t i=(m_layers.size()-1); i>rxnLayer; i--)
{
eloss += m_layers[i].GetReverseEnergyLossTotal(ze, ae, newEnergy, angle);
newEnergy = startEnergy + eloss;
}
} else {
eloss += m_layers[rxnLayer].GetReverseEnergyLossFractionalDepth(ze, ae, newEnergy, angle, m_fractionalDepthDistribution(gen.GetGenerator()));
newEnergy = startEnergy + eloss;
}
else
{
double newEnergy = startEnergy;
for(int i=0; i <= rxnLayer; i++) {
if(i == rxnLayer) {
eloss += layers[i].GetReverseEnergyLossFractionalDepth(ze, ae, newEnergy, angle, m_fractional_depth_dist(RandomGenerator::GetInstance().GetGenerator()));
newEnergy = startEnergy + eloss;
} else {
eloss += layers[i].GetReverseEnergyLossTotal(ze, ae, newEnergy, angle);
newEnergy = startEnergy + eloss;
}
for(std::size_t i=0; i < rxnLayer; i++)
{
eloss += m_layers[i].GetReverseEnergyLossTotal(ze, ae, newEnergy, angle);
newEnergy = startEnergy + eloss;
}
eloss += m_layers[rxnLayer].GetReverseEnergyLossFractionalDepth(ze, ae, newEnergy, angle, m_fractionalDepthDistribution(gen.GetGenerator()));
newEnergy = startEnergy + eloss;
}
return eloss;
}
int LayeredTarget::FindLayerContaining(int Z, int A) {
for(unsigned int i=0; i<layers.size(); i++)
if(layers[i].ContainsElement(Z, A))
std::size_t LayeredTarget::FindLayerContaining(int Z, int A)
{
for(std::size_t i=0; i<m_layers.size(); i++)
{
if(m_layers[i].ContainsElement(Z, A))
return i;
}
return -1;
return m_layers.size();
}

View File

@ -21,25 +21,25 @@ Written by G.W. McCann Aug. 2020
namespace Mask {
class LayeredTarget {
class LayeredTarget
{
public:
LayeredTarget();
~LayeredTarget();
void AddLayer(std::vector<int>& Z, std::vector<int>& A, std::vector<int>& stoich, double thickness);
double GetProjectileEnergyLoss(int zp, int ap, double startEnergy, int rxnLayer, double angle);
double GetEjectileEnergyLoss(int ze, int ae, double startEnergy, int rxnLayer, double angle);
double GetEjectileReverseEnergyLoss(int ze, int ae, double startEnergy, int rxnLayer, double angle);
int FindLayerContaining(int Z, int A);
inline int GetNumberOfLayers() { return layers.size(); }
inline void SetName(std::string& n) { name = n; }
inline const Target& GetLayerInfo(int index) { return layers[index]; }
inline const std::string& GetName() { return name; }
void AddLayer(const std::vector<int>& Z, const std::vector<int>& A, const std::vector<int>& stoich, double thickness);
double GetProjectileEnergyLoss(int zp, int ap, double startEnergy, std::size_t rxnLayer, double angle);
double GetEjectileEnergyLoss(int ze, int ae, double startEnergy, std::size_t rxnLayer, double angle);
double GetEjectileReverseEnergyLoss(int ze, int ae, double startEnergy, std::size_t rxnLayer, double angle);
std::size_t FindLayerContaining(int Z, int A);
std::size_t GetNumberOfLayers() { return m_layers.size(); }
void SetName(std::string& n) { m_name = n; }
const Target& GetLayerInfo(int index) { return m_layers[index]; }
const std::string& GetName() { return m_name; }
private:
std::vector<Target> layers;
std::string name;
std::uniform_real_distribution<double> m_fractional_depth_dist;
std::vector<Target> m_layers;
std::string m_name;
std::uniform_real_distribution<double> m_fractionalDepthDistribution;
};
}

View File

@ -3,33 +3,38 @@
namespace Mask {
double P_l(int l, double x) {
if(l == 0) {
double P_l(int l, double x)
{
if(l == 0)
return 1.0;
} else if (l == 1) {
else if (l == 1)
return x;
} else {
else
return (2.0*l - 1.0)/l*x*P_l(l-1, x) - (l-1.0)/l*P_l(l-2, x);
}
}
double Normed_P_l_sq(int l, double x) {
double Normed_P_l_sq(int l, double x)
{
return (2.0*l+1.0)/2.0*std::pow(P_l(l, x), 2.0);
}
double P_0(double x) {
double P_0(double x)
{
return 1.0;
}
double P_1(double x) {
double P_1(double x)
{
return x;
}
double P_2(double x) {
double P_2(double x)
{
return 0.5*(3.0*x*x -1.0);
}
double P_l_ROOT(double* x, double* pars) {
double P_l_ROOT(double* x, double* pars)
{
return P_l(pars[0], x[0]);
}

View File

@ -4,7 +4,7 @@
namespace Mask {
double P_l(int l, double x);
double P_l_ROOT(double* x, double* pars);
double P_l_ROOT(double* x, double* pars); //Only for use with ROOT cern in plotting
double Normed_P_l_sq(int l, double x);
double P_0(double x);

View File

@ -0,0 +1,7 @@
#ifdef __CLING__
#pragma link C++ struct Mask::Nucleus+;
#pragma link C++ class std::vector<Mask::Nucleus>+;
#pragma link C++ class std::string+;
#endif

View File

@ -1,19 +1,21 @@
#include "MaskApp.h"
#include "MaskFile.h"
#include <fstream>
#include <iostream>
#include "TFile.h"
#include "TTree.h"
namespace Mask {
MaskApp::MaskApp() :
m_sys(nullptr)
m_system(nullptr)
{
std::cout<<"----------GWM Kinematics Simulation----------"<<std::endl;
}
MaskApp::~MaskApp()
{
if(m_sys) delete m_sys;
delete m_system;
}
bool MaskApp::LoadConfig(const std::string& filename)
@ -28,67 +30,35 @@ namespace Mask {
std::string junk;
getline(input, junk);
input>>junk>>m_outfile_name;
input>>junk>>m_outputName;
std::vector<int> avec, zvec, svec;
int z, a, s;
getline(input, junk);
getline(input, junk);
input>>junk>>junk;
m_rxn_type = GetRxnTypeFromString(junk);
getline(input, junk);
getline(input, junk);
switch(m_rxn_type)
while(input>>junk)
{
case RxnType::PureDecay:
{
m_sys = new DecaySystem();
m_rxn_type = RxnType::PureDecay;
for(int i=0; i<2; i++) {
input>>z>>a;
avec.push_back(a);
zvec.push_back(z);
}
if(junk == "begin_nuclei(Z,A)")
continue;
else if (junk == "end_nuclei(Z,A)")
break;
}
case RxnType::OneStepRxn:
else
{
m_sys = new OneStepSystem();
m_rxn_type = RxnType::OneStepRxn;
for(int i=0; i<3; i++) {
input>>z>>a;
avec.push_back(a);
zvec.push_back(z);
}
break;
z = std::stoi(junk);
input>>a;
zvec.push_back(z);
avec.push_back(a);
}
case RxnType::TwoStepRxn:
{
m_sys = new TwoStepSystem();
m_rxn_type = RxnType::TwoStepRxn;
for(int i=0; i<4; i++) {
input>>z>>a;
avec.push_back(a);
zvec.push_back(z);
}
break;
}
case RxnType::ThreeStepRxn:
{
m_sys = new ThreeStepSystem();
m_rxn_type = RxnType::ThreeStepRxn;
for(int i=0; i<5; i++) {
input>>z>>a;
avec.push_back(a);
zvec.push_back(z);
}
break;
}
default:
return false;
}
m_sys->SetNuclei(zvec, avec);
m_system = CreateSystem(zvec, avec);
if(m_system == nullptr)
{
std::cerr<<"Failure to parse reaction system... configuration not loaded."<<std::endl;
return false;
}
int nlayers;
double thickness;
getline(input, junk);
@ -110,78 +80,33 @@ namespace Mask {
input>>z>>a>>s;
zvec.push_back(z); avec.push_back(a); svec.push_back(s);
}
m_sys->AddTargetLayer(zvec, avec, svec, thickness);
m_system->AddTargetLayer(zvec, avec, svec, thickness);
input>>junk;
}
std::cout<<"Reaction equation: "<<GetSystemName()<<std::endl;
double par1, par2;
std::string dfile1, dfile2;
std::string thetaTypeString;
getline(input, junk);
getline(input, junk);
input>>junk>>m_nsamples;
input>>junk>>par1>>junk>>par2;
m_sys->SetBeamDistro(par1, par2);
input>>junk>>par1;
switch(m_rxn_type)
{
case RxnType::PureDecay : break;
case RxnType::None : break;
case RxnType::OneStepRxn :
{
dynamic_cast<OneStepSystem*>(m_sys)->SetReactionThetaType(par1);
break;
}
case RxnType::TwoStepRxn :
{
dynamic_cast<TwoStepSystem*>(m_sys)->SetReactionThetaType(par1);
break;
}
case RxnType::ThreeStepRxn :
{
dynamic_cast<ThreeStepSystem*>(m_sys)->SetReactionThetaType(par1);
break;
}
}
m_system->SetBeamDistro(par1, par2);
input>>junk>>thetaTypeString;
m_system->SetReactionThetaType(StringToRxnThetaType(thetaTypeString));
input>>junk>>par1>>junk>>par2;
m_sys->SetTheta1Range(par1, par2);
m_system->SetTheta1Range(par1, par2);
input>>junk>>par1>>junk>>par2;
m_sys->SetPhi1Range(par1, par2);
m_system->SetPhi1Range(par1, par2);
input>>junk>>par1>>junk>>par2;
m_sys->SetExcitationDistro(par1, par2);
m_system->SetExcitationDistro(par1, par2);
input>>junk>>dfile1;
input>>junk>>dfile2;
switch(m_rxn_type)
{
case RxnType::PureDecay : break;
case RxnType::None : break;
case RxnType::OneStepRxn :
{
DecaySystem* this_sys = dynamic_cast<DecaySystem*>(m_sys);
this_sys->SetDecay1Distribution(dfile1);
std::cout<<"Decay1 angular momentum: "<<this_sys->GetDecay1AngularMomentum()<<std::endl;
std::cout<<"Decay1 total branching ratio: "<<this_sys->GetDecay1BranchingRatio()<<std::endl;
break;
}
case RxnType::TwoStepRxn :
{
TwoStepSystem* this_sys = dynamic_cast<TwoStepSystem*>(m_sys);
this_sys->SetDecay1Distribution(dfile1);
std::cout<<"Decay1 angular momentum: "<<this_sys->GetDecay1AngularMomentum()<<std::endl;
std::cout<<"Decay1 total branching ratio: "<<this_sys->GetDecay1BranchingRatio()<<std::endl;
break;
}
case RxnType::ThreeStepRxn :
{
ThreeStepSystem* this_sys = dynamic_cast<ThreeStepSystem*>(m_sys);
this_sys->SetDecay1Distribution(dfile1);
this_sys->SetDecay2Distribution(dfile2);
std::cout<<"Decay1 angular momentum: "<<this_sys->GetDecay1AngularMomentum()<<" Decay2 angular momentum: "<<this_sys->GetDecay2AngularMomentum()<<std::endl;
std::cout<<"Decay1 total branching ratio: "<<this_sys->GetDecay1BranchingRatio()<<" Decay2 total branching ratio: "<<this_sys->GetDecay2BranchingRatio()<<std::endl;
break;
}
}
m_system->SetDecay1Distribution(dfile1);
m_system->SetDecay2Distribution(dfile2);
std::cout<<"Number of samples: "<<GetNumberOfSamples()<<std::endl;
@ -192,13 +117,14 @@ namespace Mask {
void MaskApp::Run() {
std::cout<<"Running simulation..."<<std::endl;
if(m_sys == nullptr)
if(m_system == nullptr)
{
return;
}
MaskFile output(m_outfile_name, MaskFile::FileType::write);
output.WriteHeader(m_rxn_type, m_nsamples);
TFile* output = TFile::Open(m_outputName.c_str(), "RECREATE");
TTree* tree = new TTree("SimTree", "SimTree");
tree->Branch("nuclei", m_system->GetNuclei());
//For progress tracking
uint32_t percent5 = 0.05*m_nsamples;
@ -214,11 +140,12 @@ namespace Mask {
std::cout<<"\rPercent complete: "<<npercent*5<<"%"<<std::flush;
}
m_sys->RunSystem();
output.WriteData(m_sys->GetNuclei());
m_system->RunSystem();
tree->Fill();
}
output.Close();
tree->Write(tree->GetName(), TObject::kOverwrite);
output->Close();
std::cout<<std::endl;
std::cout<<"Complete."<<std::endl;

37
src/Mask/MaskApp.h Normal file
View File

@ -0,0 +1,37 @@
#ifndef MASKAPP_H
#define MASKAPP_H
#include "ReactionSystem.h"
#include "DecaySystem.h"
#include "OneStepSystem.h"
#include "TwoStepSystem.h"
#include "ThreeStepSystem.h"
#include "RxnType.h"
namespace Mask {
class MaskApp
{
public:
MaskApp();
~MaskApp();
bool LoadConfig(const std::string& filename);
bool SaveConfig(const std::string& filename);
int GetNumberOfSamples() const { return m_nsamples; }
const std::string GetSystemName() const { return m_system == nullptr ? "Invalid System" : m_system->GetSystemEquation(); }
const std::string GetOutputName() const { return m_outputName; }
const RxnType GetReactionType() const { return m_rxnType; }
void Run();
private:
ReactionSystem* m_system;
std::string m_outputName;
RxnType m_rxnType;
int m_nsamples;
};
}
#endif

View File

@ -1,364 +0,0 @@
#include "MaskFile.h"
#include <iostream>
#include <iomanip>
#include <sstream>
/*
FORMAT
HEADER (contains rxntype & nuclei numbers & beam kinetic energy) (64 bits, 8 bytes)
NSAMPLES(32bit) RXNTYPE(32bit)
end HEADER
There are NSAMPLES * (number of saved nuclei) data in the file. The number of nuclei saved is related to the
RXNTYPE. All nuclei (target, projectile, ejectile, residual, break1, etc...) are saved. A datum is as follows:
DATUM (contains kinematic data for a nucleus) (384 bits, 48 bytes)
Z(32bit) A(32bit) DETECTFLAG(32bit) E(64bit) KE(64bit) P(64bit) THETA(64bit) PHI(64bit)
end DATUM
*/
namespace Mask {
MaskFile::MaskFile() :
file_type(MaskFile::FileType::none), filename(""), buffer_position(0), buffer_end(0), data_size(0), buffersize_bytes(0), file()
{
}
MaskFile::MaskFile(const std::string& name, MaskFile::FileType type) :
file_type(type), filename(name), buffer_position(0), buffer_end(0), data_size(0), buffersize_bytes(0), file()
{
Open(filename, type);
}
bool MaskFile::Open(const std::string& name, MaskFile::FileType type) {
if(IsOpen()) {
std::cerr<<"Attempted to open file that is already open!"<<std::endl;
return false;
}
if(type == FileType::read) {
file.open(name, std::ios::in);
buffer_position = 0;
} else if (type == FileType::write) {
file.open(name, std::ios::out | std::ios::trunc);
} else if (type == FileType::append) {
file.open(name, std::ios::out | std::ios::app);
} else {
std::cerr<<"Invalid FileType at MaskFile::Open()"<<std::endl;
return IsOpen();
}
return IsOpen();
}
void MaskFile::Close() {
//Final flush (if necessary)
if(buffer_position > 0 && buffer_position < buffersize_bytes && (file_type == FileType::write || file_type == FileType::append)) {
file.write(data_buffer.data(), buffer_position);
}
file.close();
}
void MaskFile::WriteHeader(RxnType rxn_type, int nsamples) {
m_rxn_type = rxn_type;
switch(rxn_type)
{
case RxnType::PureDecay :
{
data_size = 3 * ( 5 * double_size + 2 * int_size + bool_size);
break;
}
case RxnType::OneStepRxn :
{
data_size = 4 * ( 5 * double_size + 2 * int_size + bool_size);
break;
}
case RxnType::TwoStepRxn :
{
data_size = 6 * ( 5 * double_size + 2 * int_size + bool_size);
break;
}
case RxnType::ThreeStepRxn :
{
data_size = 8 * ( 5 * double_size + 2 * int_size + bool_size);
break;
}
case RxnType::None :
{
std::cerr<<"Invalid RxnType at MaskFile::WriteHeader!"<<std::endl;
return;
}
}
buffersize_bytes = buffersize * data_size; //buffersize_bytes = # of events * size of an event
data_buffer.resize(buffersize_bytes);
uint32_t type_value = GetIntFromRxnType(m_rxn_type);
file.write((char*) &nsamples, int_size);
file.write((char*) &type_value, int_size);
}
MaskFileHeader MaskFile::ReadHeader() {
MaskFileHeader header;
std::vector<char> temp_buffer(4);
file.read(temp_buffer.data(), 4);
header.nsamples = *(int*)(&temp_buffer[0]);
file.read(temp_buffer.data(), 4);
uint32_t type_value = *(uint32_t*)(&temp_buffer[0]);
m_rxn_type = GetRxnTypeFromInt(type_value);
switch(m_rxn_type)
{
case RxnType::PureDecay:
{
data_size = 3 * ( 5 * double_size + 2 * int_size + bool_size);
break;
}
case RxnType::OneStepRxn:
{
data_size = 4 * ( 5 * double_size + 2 * int_size + bool_size);
break;
}
case RxnType::TwoStepRxn:
{
data_size = 6 * ( 5 * double_size + 2 * int_size + bool_size);
break;
}
case RxnType::ThreeStepRxn:
{
data_size = 8 * ( 5 * double_size + 2 * int_size + bool_size);
break;
}
case RxnType::None:
{
std::cerr<<"Unexpected reaction type at MaskFile::ReadHeader (rxn type = "<<GetIntFromRxnType(m_rxn_type)<<")! Returning"<<std::endl;
return header;
}
}
buffersize_bytes = buffersize * data_size;//buffersize_bytes = size of a datum * # of events
header.rxn_type = m_rxn_type;
data_buffer.resize(buffersize_bytes);
return header;
}
void MaskFile::WriteData(const std::vector<Nucleus>& data) {
char* data_pointer;
double datum;
int number;
bool flag;
std::size_t j;
for(unsigned int i=0; i<data.size(); i++) {
number = data[i].GetZ();
data_pointer = (char*) &number;
for(j=0; j<int_size; j++) {
data_buffer[buffer_position] = *(data_pointer + j);
buffer_position++;
}
number = data[i].GetA();
data_pointer = (char*) &number;
for(j=0; j<int_size; j++) {
data_buffer[buffer_position] = *(data_pointer + j);
buffer_position++;
}
flag = data[i].IsDetected();
data_pointer = (char*) &flag;
for(j=0; j<bool_size; j++) {
data_buffer[buffer_position] = *(data_pointer + j);
buffer_position++;
}
datum = data[i].GetE();
data_pointer = (char*) &datum;
for(j=0; j<double_size; j++) {
data_buffer[buffer_position] = *(data_pointer + j);
buffer_position++;
}
datum = data[i].GetKE();
data_pointer = (char*) &datum;
for(j=0; j<double_size; j++) {
data_buffer[buffer_position] = *(data_pointer + j);
buffer_position++;
}
datum = data[i].GetP();
data_pointer = (char*) &datum;
for(j=0; j<double_size; j++) {
data_buffer[buffer_position] = *(data_pointer + j);
buffer_position++;
}
datum = data[i].GetTheta();
data_pointer = (char*) &datum;
for(j=0; j<double_size; j++) {
data_buffer[buffer_position] = *(data_pointer + j);
buffer_position++;
}
datum = data[i].GetPhi();
data_pointer = (char*) &datum;
for(j=0; j<double_size; j++) {
data_buffer[buffer_position] = *(data_pointer + j);
buffer_position++;
}
}
//Flush the buffer when it is full, and reset the position.
if(buffer_position == buffersize_bytes) {
file.write(data_buffer.data(), data_buffer.size());
buffer_position = 0;
}
}
void MaskFile::WriteData(const MaskFileData& data) {
char* data_pointer;
double datum;
int number;
bool flag;
std::size_t j;
for(unsigned int i=0; i<data.Z.size(); i++) {
number = data.Z[i];
data_pointer = (char*) &number;
for(j=0; j<int_size; j++) {
data_buffer[buffer_position] = *(data_pointer + j);
buffer_position++;
}
number = data.A[i];
data_pointer = (char*) &number;
for(j=0; j<int_size; j++) {
data_buffer[buffer_position] = *(data_pointer + j);
buffer_position++;
}
flag = data.detect_flag[i];
data_pointer = (char*) &flag;
for(j=0; j<bool_size; j++) {
data_buffer[buffer_position] = *(data_pointer + j);
buffer_position++;
}
datum = data.E[i];
data_pointer = (char*) &datum;
for(j=0; j<double_size; j++) {
data_buffer[buffer_position] = *(data_pointer + j);
buffer_position++;
}
datum = data.KE[i];
data_pointer = (char*) &datum;
for(j=0; j<double_size; j++) {
data_buffer[buffer_position] = *(data_pointer + j);
buffer_position++;
}
datum = data.p[i];
data_pointer = (char*) &datum;
for(j=0; j<double_size; j++) {
data_buffer[buffer_position] = *(data_pointer + j);
buffer_position++;
}
datum = data.theta[i];
data_pointer = (char*) &datum;
for(j=0; j<double_size; j++) {
data_buffer[buffer_position] = *(data_pointer + j);
buffer_position++;
}
datum = data.phi[i];
data_pointer = (char*) &datum;
for(j=0; j<double_size; j++) {
data_buffer[buffer_position] = *(data_pointer + j);
buffer_position++;
}
}
//Flush the buffer when it is full, and reset the position.
if(buffer_position == buffersize_bytes) {
file.write(data_buffer.data(), data_buffer.size());
buffer_position = 0;
}
}
/*
Read data from the buffer and submit it to the client side as a MaskFileData struct.
When file reaches the end of the file (no more data to read), an empty MaskFileData with
eof == true is sent out signaling that the file is finished.
Should be used like
Mask::MaskFile input(file, Mask::MaskFile::FileType::read);
Mask::MaskFileHeader header = input.ReadHeader();
Mask::MaskFileData data;
while(true) {
data = input.ReadData();
if(data.eof) break;
Do some stuff...
}
input.Close();
Good luck
*/
MaskFileData MaskFile::ReadData() {
MaskFileData data;
//Fill the buffer when needed, reset the positon, and find the end
if(buffer_position == data_buffer.size() || buffer_position == buffer_end) {
file.read(data_buffer.data(), buffersize_bytes);
buffer_position = 0;
buffer_end = file.gcount();
if(buffer_end == 0 && file.eof()) {
data.eof = true;
return data;
}
}
uint64_t local_end = buffer_position + data_size;
if(local_end > buffer_end) {
std::cerr<<"Attempting to read past end of file at MaskFile::ReadData! Returning empty"<<std::endl;
data.eof = true;
return data;
}
while(buffer_position < local_end) {
data.Z.push_back(*(int*)(&data_buffer[buffer_position]));
buffer_position += int_size;
data.A.push_back(*(int*)(&data_buffer[buffer_position]));
buffer_position += int_size;
data.detect_flag.push_back(*(bool*)(&data_buffer[buffer_position]));
buffer_position += bool_size;
data.E.push_back(*(double*)(&data_buffer[buffer_position]));
buffer_position += double_size;
data.KE.push_back(*(double*)(&data_buffer[buffer_position]));
buffer_position += double_size;
data.p.push_back(*(double*)(&data_buffer[buffer_position]));
buffer_position += double_size;
data.theta.push_back(*(double*)(&data_buffer[buffer_position]));
buffer_position += double_size;
data.phi.push_back(*(double*)(&data_buffer[buffer_position]));
buffer_position += double_size;
}
return data;
}
};

View File

@ -10,38 +10,41 @@ Written by G.W. McCann Aug. 2020
*/
#include "MassLookup.h"
#include "KinematicsExceptions.h"
#include <sstream>
namespace Mask {
MassLookup::MassLookup() {
MassLookup* MassLookup::s_instance = new MassLookup();
MassLookup::MassLookup()
{
std::ifstream massfile("etc/mass.txt");
if(massfile.is_open()) {
std::string junk, A, element;
int Z;
KeyPair key;
if(massfile.is_open())
{
std::string junk, element;
double atomicMassBig, atomicMassSmall, isotopicMass;
getline(massfile,junk);
getline(massfile,junk);
while(massfile>>junk) {
massfile>>Z>>A>>element>>atomicMassBig>>atomicMassSmall;
isotopicMass = (atomicMassBig + atomicMassSmall*1e-6 - Z*electron_mass)*u_to_mev;
std::string key = "("+std::to_string(Z)+","+A+")";
massTable[key] = isotopicMass;
elementTable[Z] = element;
while(massfile>>junk)
{
massfile>>key.Z>>key.A>>element>>atomicMassBig>>atomicMassSmall;
isotopicMass = (atomicMassBig + atomicMassSmall*1e-6 - key.Z*electron_mass)*u_to_mev;
massTable[key.GetID()] = isotopicMass;
elementTable[key.GetID()] = std::to_string(key.A) + element;
}
} else {
throw MassFileException();
}
else
throw MassFileException();
}
MassLookup::~MassLookup() {
}
MassLookup::~MassLookup() {}
//Returns nuclear mass in MeV
double MassLookup::FindMass(int Z, int A) {
std::string key = "("+std::to_string(Z)+","+std::to_string(A)+")";
auto data = massTable.find(key);
double MassLookup::FindMass(uint32_t Z, uint32_t A)
{
KeyPair key({Z, A});
auto data = massTable.find(key.GetID());
if(data == massTable.end())
throw MassException();
@ -49,13 +52,14 @@ namespace Mask {
}
//returns element symbol
std::string MassLookup::FindSymbol(int Z, int A) {
auto data = elementTable.find(Z);
std::string MassLookup::FindSymbol(uint32_t Z, uint32_t A)
{
KeyPair key({Z, A});
auto data = elementTable.find(key.GetID());
if(data == elementTable.end())
throw MassException();
std::string fullsymbol = std::to_string(A) + data->second;
return fullsymbol;
return data->second;
}
}

View File

@ -18,22 +18,35 @@ Converted to true singleton to simplify usage -- Aug. 2021 GWM
namespace Mask {
class MassLookup {
class MassLookup
{
public:
struct KeyPair
{
uint32_t Z;
uint32_t A;
//Use szudzik pairing method to make unqiue key out of two unsigned ints. Use size_t as extra safety.
std::size_t GetID()
{
return Z >= A ? Z*Z + Z + A : A*A + Z;
}
};
~MassLookup();
double FindMass(int Z, int A);
double FindMassU(int Z, int A) { return FindMass(Z, A)/u_to_mev; }
std::string FindSymbol(int Z, int A);
double FindMass(uint32_t Z, uint32_t A);
double FindMassU(uint32_t Z, uint32_t A) { return FindMass(Z, A)/u_to_mev; }
std::string FindSymbol(uint32_t Z, uint32_t A);
static MassLookup& GetInstance() {
static MassLookup s_instance;
return s_instance;
}
static MassLookup& GetInstance() { return *s_instance; }
private:
MassLookup();
std::unordered_map<std::string, double> massTable;
std::unordered_map<int, std::string> elementTable;
static MassLookup* s_instance;
std::unordered_map<std::size_t, double> massTable;
std::unordered_map<std::size_t, std::string> elementTable;
//constants
static constexpr double u_to_mev = 931.4940954;

View File

@ -1,47 +1,17 @@
/*
Nucleus.cpp
Nucleus is a derived class of Vec4. A nucleus is the kinematics is essentially a 4 vector with the
additional properties of the number of total nucleons (A), the number of protons (Z), a ground state mass,
an exctitation energy, and an isotopic symbol.
--GWM Jan 2021
*/
#include "Nucleus.h"
#include "MassLookup.h"
namespace Mask {
Nucleus::Nucleus () :
Vec4(), m_z(0), m_a(0), m_gs_mass(0), m_theta_cm(0), m_symbol(""), m_detectFlag(false)
{
}
Nucleus::Nucleus(int Z, int A) :
Vec4(), m_z(Z), m_a(A), m_theta_cm(0), m_detectFlag(false)
{
m_gs_mass = MassLookup::GetInstance().FindMass(Z, A);
m_symbol = MassLookup::GetInstance().FindSymbol(Z, A);
SetVectorCartesian(0,0,0,m_gs_mass); //by defualt a nucleus has mass given by the g.s.
}
Nucleus::Nucleus(int Z, int A, double px, double py, double pz, double E) :
Vec4(px, py, pz, E), m_z(Z), m_a(A)
{
m_gs_mass = MassLookup::GetInstance().FindMass(Z, A);
m_symbol = MassLookup::GetInstance().FindSymbol(Z, A);
}
Nucleus::~Nucleus() {}
bool Nucleus::SetIsotope(int Z, int A) {
if(Z>A) return false;
m_z = Z;
m_a = A;
m_gs_mass = MassLookup::GetInstance().FindMass(Z, A);
m_symbol = MassLookup::GetInstance().FindSymbol(Z, A);
SetVectorCartesian(0,0,0,m_gs_mass);
return true;
}
Nucleus CreateNucleus(uint32_t z, uint32_t a)
{
Nucleus nuc;
nuc.Z = z;
nuc.A = a;
nuc.groundStateMass = MassLookup::GetInstance().FindMass(z, a);
nuc.isotopicSymbol = MassLookup::GetInstance().FindSymbol(z, a);
nuc.vec4 = ROOT::Math::PxPyPzEVector(0., 0., 0., nuc.groundStateMass);
return nuc;
}
bool EnforceDictionaryLinked() { return true; }
}

59
src/Mask/Nucleus.h Normal file
View File

@ -0,0 +1,59 @@
/*
Nucleus.h
Nucleus is a derived class of Vec4. A nucleus is the kinematics is essentially a 4 vector with the
additional properties of the number of total nucleons (A), the number of protons (Z), a ground state mass,
an exctitation energy, and an isotopic symbol.
--GWM Jan 2021
*/
#ifndef NUCLEUS_H
#define NUCLEUS_H
#include <string>
#include <vector>
#include "Math/Vector4D.h"
#include "MassLookup.h"
namespace Mask {
struct Nucleus
{
void SetVec4Spherical(double theta, double phi, double p, double E)
{
vec4.SetPxPyPzE(std::sin(theta)*std::cos(phi)*p,
std::sin(theta)*std::sin(phi)*p,
std::cos(theta)*p,
E
);
}
double GetKE() const
{
return vec4.E() - vec4.M();
}
double GetExcitationEnergy() const
{
return vec4.M() - groundStateMass;
}
uint32_t Z = 0;
uint32_t A = 0;
double groundStateMass = 0.0;
std::string isotopicSymbol = "";
double thetaCM = 0.0;
ROOT::Math::PxPyPzEVector vec4;
bool isDetected = false;
double detectedKE = 0.0;
double detectedTheta = 0.0;
double detectedPhi = 0.0;
};
Nucleus CreateNucleus(uint32_t z, uint32_t a);
bool EnforceDictionaryLinked();
};
#endif

View File

@ -1,68 +1,76 @@
#include "OneStepSystem.h"
#include "RandomGenerator.h"
#include <sstream>
namespace Mask {
OneStepSystem::OneStepSystem() :
ReactionSystem()
{
nuclei.resize(4);
m_nuclei.resize(4);
}
OneStepSystem::OneStepSystem(std::vector<int>& z, std::vector<int>& a) :
OneStepSystem::OneStepSystem(const std::vector<int>& z, const std::vector<int>& a) :
ReactionSystem()
{
nuclei.resize(4);
m_nuclei.resize(4);
SetNuclei(z, a);
}
OneStepSystem::~OneStepSystem() {}
bool OneStepSystem::SetNuclei(std::vector<int>& z, std::vector<int>& a) {
if(z.size() != a.size() || z.size() != 3) {
bool OneStepSystem::SetNuclei(const std::vector<int>& z, const std::vector<int>& a)
{
if(z.size() != a.size() || z.size() != 3)
return false;
}
step1.SetNuclei(z[0], a[0], z[1], a[1], z[2], a[2]);
int zr = z[0] + z[1] - z[2];
int ar = a[0] + a[1] - a[2];
m_nuclei[0] = CreateNucleus(z[0], a[0]); //target
m_nuclei[1] = CreateNucleus(z[1], a[1]); //projectile
m_nuclei[2] = CreateNucleus(z[2], a[2]); //ejectile
m_nuclei[3] = CreateNucleus(zr, ar); //residual
m_step1.BindNuclei(&(m_nuclei[0]), &(m_nuclei[1]), &(m_nuclei[2]), &(m_nuclei[3]));
SetSystemEquation();
return true;
}
const std::vector<Nucleus>& OneStepSystem::GetNuclei()
std::vector<Nucleus>* OneStepSystem::GetNuclei()
{
nuclei[0] = step1.GetTarget();
nuclei[1] = step1.GetProjectile();
nuclei[2] = step1.GetEjectile();
nuclei[3] = step1.GetResidual();
return nuclei;
return &m_nuclei;
}
void OneStepSystem::LinkTarget() {
step1.SetLayeredTarget(&target);
void OneStepSystem::LinkTarget()
{
m_step1.SetLayeredTarget(&m_target);
rxnLayer = target.FindLayerContaining(step1.GetTarget().GetZ(), step1.GetTarget().GetA());
if(rxnLayer != -1) {
step1.SetRxnLayer(rxnLayer);
target_set_flag = true;
} else {
throw ReactionLayerException();
m_rxnLayer = m_target.FindLayerContaining(m_nuclei[0].Z, m_nuclei[0].A);
if(m_rxnLayer != m_target.GetNumberOfLayers())
{
m_step1.SetRxnLayer(m_rxnLayer);
m_isTargetSet = true;
}
else
throw ReactionLayerException();
}
void OneStepSystem::SetSystemEquation() {
m_sys_equation = step1.GetTarget().GetIsotopicSymbol();
m_sys_equation += "(";
m_sys_equation += step1.GetProjectile().GetIsotopicSymbol();
m_sys_equation += ", ";
m_sys_equation += step1.GetEjectile().GetIsotopicSymbol();
m_sys_equation += ")";
m_sys_equation += step1.GetResidual().GetIsotopicSymbol();
void OneStepSystem::SetSystemEquation()
{
std::stringstream stream;
stream << m_nuclei[0].isotopicSymbol << "("
<< m_nuclei[1].isotopicSymbol << ", "
<< m_nuclei[2].isotopicSymbol << ")"
<< m_nuclei[3].isotopicSymbol;
m_sysEquation = stream.str();
}
void OneStepSystem::RunSystem() {
//Link up the target if it hasn't been done yet
if(!target_set_flag) {
if(!m_isTargetSet)
{
LinkTarget();
}
@ -72,13 +80,13 @@ namespace Mask {
double rxnPhi = (*m_phi1Range)(RandomGenerator::GetInstance().GetGenerator());
double residEx = (*m_exDist)(RandomGenerator::GetInstance().GetGenerator());
step1.SetBeamKE(bke);
step1.SetPolarRxnAngle(rxnTheta);
step1.SetAzimRxnAngle(rxnPhi);
step1.SetExcitation(residEx);
m_step1.SetBeamKE(bke);
m_step1.SetPolarRxnAngle(rxnTheta);
m_step1.SetAzimRxnAngle(rxnPhi);
m_step1.SetExcitation(residEx);
step1.TurnOnResidualEloss();
step1.Calculate();
m_step1.SetResidualEnergyLoss(true);
m_step1.Calculate();
}
}

30
src/Mask/OneStepSystem.h Normal file
View File

@ -0,0 +1,30 @@
#ifndef ONESTEPSYSTEM_H
#define ONESTEPSYSTEM_H
#include "ReactionSystem.h"
namespace Mask {
class OneStepSystem: public ReactionSystem {
public:
OneStepSystem();
OneStepSystem(const std::vector<int>& z, const std::vector<int>& a);
~OneStepSystem();
bool SetNuclei(const std::vector<int>& z, const std::vector<int>& a) override;
void RunSystem() override;
std::vector<Nucleus>* GetNuclei() override;
virtual void SetReactionThetaType(RxnThetaType type) override { m_step1.SetEjectileThetaType(type); };
private:
void LinkTarget() override;
void SetSystemEquation() override;
Reaction m_step1;
};
}
#endif

View File

@ -1,11 +1,13 @@
#include "RandomGenerator.h"
namespace Mask {
RandomGenerator::RandomGenerator() {
RandomGenerator* RandomGenerator::s_instance = new RandomGenerator();
RandomGenerator::RandomGenerator()
{
std::random_device rd;
rng.seed(rd());
}
RandomGenerator::~RandomGenerator() {
}
RandomGenerator::~RandomGenerator() {}
}

View File

@ -0,0 +1,24 @@
#ifndef RANDOMGENERATOR_H
#define RANDOMGENERATOR_H
#include <random>
namespace Mask {
class RandomGenerator
{
public:
~RandomGenerator();
std::mt19937& GetGenerator() { return rng; }
static RandomGenerator& GetInstance() { return *s_instance; }
private:
RandomGenerator();
static RandomGenerator* s_instance;
std::mt19937 rng;
};
}
#endif

View File

@ -1,4 +1,4 @@
/*
/*ayer
Reaction.cpp
Reaction is a class which implements either a decay or scattering reaction. As such it requires either
3 (decay) or 4 (scattering) nuclei to perform any calcualtions. I also links together the target, which provides
@ -9,29 +9,33 @@
#include "Reaction.h"
#include "KinematicsExceptions.h"
#include "Math/Boost.h"
namespace Mask {
Reaction::Reaction() :
target(nullptr), m_bke(0), m_theta(0), m_phi(0), m_ex(0), rxnLayer(0), m_eject_theta_type(lab), nuc_initFlag(false), resid_elossFlag(false)
m_target(nullptr), m_projectile(nullptr), m_ejectile(nullptr), m_residual(nullptr), m_layeredTarget(nullptr),
m_bke(0), m_theta(0), m_phi(0), m_ex(0), m_rxnLayer(0), m_ejectThetaType(RxnThetaType::None), m_isInit(false), m_isResidEloss(false)
{
}
Reaction::Reaction(int zt, int at, int zp, int ap, int ze, int ae) :
target(nullptr), m_bke(0), m_theta(0), m_phi(0), m_ex(0), rxnLayer(0), m_eject_theta_type(lab), resid_elossFlag(false)
Reaction::Reaction(Nucleus* target, Nucleus* projectile, Nucleus* ejectile, Nucleus* residual) :
m_target(nullptr), m_projectile(nullptr), m_ejectile(nullptr), m_residual(nullptr),
m_layeredTarget(nullptr), m_bke(0), m_theta(0), m_phi(0), m_ex(0), m_rxnLayer(0), m_ejectThetaType(RxnThetaType::None), m_isResidEloss(false)
{
SetNuclei(zt, at, zp, ap, ze, ae);
BindNuclei(target, projectile, ejectile, residual);
}
Reaction::~Reaction()
{
}
bool Reaction::Calculate() {
if(!nuc_initFlag)
bool Reaction::Calculate()
{
if(!m_isInit)
return false;
if(decayFlag) {
if(m_isDecay) {
CalculateDecay();
return true;
} else {
@ -40,203 +44,183 @@ namespace Mask {
}
}
//Deep copy of nucleus array
void Reaction::SetNuclei(const Nucleus* nucs) {
reactants[0] = nucs[0];
reactants[1] = nucs[1];
reactants[2] = nucs[2];
reactants[3] = nucs[3];
nuc_initFlag = true;
void Reaction::BindNuclei(Nucleus* target, Nucleus* projectile, Nucleus* ejectile, Nucleus* residual)
{
m_target = target;
m_projectile = projectile;
m_ejectile = ejectile;
m_residual = residual;
if(m_projectile == nullptr)
m_isDecay = true;
else
m_isDecay = false;
if(m_target == nullptr || m_ejectile == nullptr || m_residual == nullptr)
m_isInit = false;
else
m_isInit = true;
}
void Reaction::SetNuclei(int zt, int at, int zp, int ap, int ze, int ae) {
int zr, ar;
reactants[0] = Nucleus(zt, at);
reactants[2] = Nucleus(ze, ae);
if(ap == 0) {
decayFlag = true;
zr = zt - ze;
ar = at - ae;
} else {
reactants[1] = Nucleus(zp, ap);
decayFlag = false;
zr = zt + zp - ze;
ar = at + ap - ae;
}
if(zr < 0 || ar <= 0) {
nuc_initFlag = false;
} else {
reactants[3] = Nucleus(zr, ar);
nuc_initFlag = true;
}
}
void Reaction::SetBeamKE(double bke) {
if(!nuc_initFlag || decayFlag)
void Reaction::SetBeamKE(double bke)
{
if(!m_isInit || m_isDecay)
return;
m_bke = bke - target->GetProjectileEnergyLoss(reactants[1].GetZ(), reactants[1].GetA(), bke, rxnLayer, 0);
m_bke = bke - m_layeredTarget->GetProjectileEnergyLoss(m_projectile->Z, m_projectile->A, bke, m_rxnLayer, 0);
}
void Reaction::SetEjectileThetaType(int type) {
if(decayFlag) return;
if(type != center_of_mass && type != lab) return;
m_eject_theta_type = type;
void Reaction::SetEjectileThetaType(RxnThetaType type)
{
if(m_isDecay)
return;
m_ejectThetaType = type;
}
//Methods given by Iliadis in Nuclear Physics of Stars, Appendix C
//For use with lab frame restricted angles. May not give appropriate disribution for ejectile
void Reaction::CalculateReactionThetaLab() {
reactants[0].SetVectorCartesian(0.,0.,0.,reactants[0].GetGroundStateMass());
double beam_pz = std::sqrt(m_bke*(m_bke + 2.0 * reactants[1].GetGroundStateMass()));
double beam_E = m_bke + reactants[1].GetGroundStateMass();
reactants[1].SetVectorCartesian(0.,0.,beam_pz,beam_E);
void Reaction::CalculateReactionThetaLab()
{
m_target->vec4.SetPxPyPzE(0.,0.,0.,m_target->groundStateMass);
double beam_pz = std::sqrt(m_bke*(m_bke + 2.0 * m_projectile->groundStateMass));
double beam_E = m_bke + m_projectile->groundStateMass;
m_projectile->vec4.SetPxPyPzE(0.,0.,beam_pz,beam_E);
double Q = reactants[0].GetGroundStateMass() + reactants[1].GetGroundStateMass() - (reactants[2].GetGroundStateMass() + reactants[3].GetGroundStateMass() + m_ex);
double Q = m_target->groundStateMass + m_projectile->groundStateMass - (m_ejectile->groundStateMass + m_residual->groundStateMass + m_ex);
double Ethresh = -Q*(reactants[2].GetGroundStateMass()+reactants[3].GetGroundStateMass())/(reactants[2].GetGroundStateMass() + reactants[3].GetGroundStateMass() - reactants[1].GetGroundStateMass());
if(m_bke < Ethresh) {
double Ethresh = -Q*(m_ejectile->groundStateMass+m_residual->groundStateMass) /
(m_ejectile->groundStateMass + m_residual->groundStateMass - m_projectile->groundStateMass);
if(m_bke < Ethresh)
throw EnergyThresholdException();
}
double term1 = sqrt(reactants[1].GetGroundStateMass()*reactants[2].GetGroundStateMass()*m_bke)/(reactants[2].GetGroundStateMass()+reactants[3].GetGroundStateMass())*cos(m_theta);
double term2 = (m_bke*(reactants[3].GetGroundStateMass() - reactants[1].GetGroundStateMass()) + reactants[3].GetGroundStateMass()*Q)/(reactants[3].GetGroundStateMass() + reactants[2].GetGroundStateMass());
double sqrt_pos_ejectKE = term1 + sqrt(term1*term1 + term2);
double sqrt_neg_ejectKE = term1 - sqrt(term1*term1 + term2);
double term1 = std::sqrt(m_projectile->groundStateMass * m_ejectile->groundStateMass * m_bke)/
(m_ejectile->groundStateMass + m_residual->groundStateMass) * std::cos(m_theta);
double term2 = (m_bke * (m_residual->groundStateMass - m_projectile->groundStateMass) + m_residual->groundStateMass*Q) /
(m_residual->groundStateMass + m_ejectile->groundStateMass);
double sqrt_pos_ejectKE = term1 + std::sqrt(term1*term1 + term2);
double sqrt_neg_ejectKE = term1 - std::sqrt(term1*term1 + term2);
double ejectKE;
if(sqrt_pos_ejectKE > 0) {
if(sqrt_pos_ejectKE > 0)
ejectKE = sqrt_pos_ejectKE*sqrt_pos_ejectKE;
} else {
else
ejectKE = sqrt_neg_ejectKE*sqrt_neg_ejectKE;
}
double ejectP = std::sqrt(ejectKE*(ejectKE + 2.0 * reactants[2].GetGroundStateMass()));
double ejectE = ejectKE + reactants[2].GetGroundStateMass();
double ejectP = std::sqrt(ejectKE * (ejectKE + 2.0 * m_ejectile->groundStateMass));
double ejectE = ejectKE + m_ejectile->groundStateMass;
reactants[2].SetVectorSpherical(m_theta, m_phi, ejectP, ejectE);
m_ejectile->SetVec4Spherical(m_theta, m_phi, ejectP, ejectE);
reactants[3] = reactants[0] + reactants[1] - reactants[2];
m_residual->vec4 = m_target->vec4 + m_projectile->vec4 - m_ejectile->vec4;
ejectKE -= target->GetEjectileEnergyLoss(reactants[2].GetZ(), reactants[2].GetA(), ejectKE, rxnLayer, m_theta);
ejectP = std::sqrt(ejectKE*(ejectKE + 2.0 * reactants[2].GetGroundStateMass()));
ejectE = ejectKE + reactants[2].GetGroundStateMass();
reactants[2].SetVectorSpherical(m_theta, m_phi, ejectP, ejectE);
ejectKE -= m_layeredTarget->GetEjectileEnergyLoss(m_ejectile->Z, m_ejectile->A, ejectKE, m_rxnLayer, m_theta);
ejectP = std::sqrt(ejectKE*(ejectKE + 2.0 * m_ejectile->groundStateMass));
ejectE = ejectKE + m_ejectile->groundStateMass;
m_ejectile->SetVec4Spherical(m_theta, m_phi, ejectP, ejectE);
if(resid_elossFlag) {
double residKE = reactants[3].GetKE() - target->GetEjectileEnergyLoss(reactants[3].GetZ(), reactants[3].GetA(), reactants[3].GetKE(), rxnLayer, reactants[3].GetTheta());
double residP = std::sqrt(residKE*(residKE + 2.0*reactants[3].GetInvMass()));
double residE = residKE + reactants[3].GetInvMass();
reactants[3].SetVectorSpherical(reactants[3].GetTheta(), reactants[3].GetPhi(), residP, residE);
if(m_isResidEloss) {
double residKE = m_residual->GetKE() - m_layeredTarget->GetEjectileEnergyLoss(m_residual->Z, m_residual->A, m_residual->GetKE(),
m_rxnLayer, m_residual->vec4.Theta());
double residP = std::sqrt(residKE*(residKE + 2.0*m_residual->vec4.M()));
double residE = residKE + m_residual->vec4.M();
m_residual->SetVec4Spherical(m_residual->vec4.Theta(), m_residual->vec4.Phi(), residP, residE);
}
}
//Methods from original ANASEN. Gives proper distribution for inverse kinematics.
void Reaction::CalculateReactionThetaCM() {
void Reaction::CalculateReactionThetaCM()
{
//Target assumed at rest, with 0 excitation energy
reactants[0].SetVectorCartesian(0.,0.,0.,reactants[0].GetGroundStateMass());
double beam_pz = std::sqrt(m_bke*(m_bke + 2.0 * reactants[1].GetGroundStateMass()));
double beam_E = m_bke + reactants[1].GetGroundStateMass();
reactants[1].SetVectorCartesian(0.,0.,beam_pz,beam_E);
m_target->vec4.SetPxPyPzE(0.,0.,0.,m_target->groundStateMass);
double beam_pz = std::sqrt(m_bke*(m_bke + 2.0 * m_projectile->groundStateMass));
double beam_E = m_bke + m_projectile->groundStateMass;
m_projectile->vec4.SetPxPyPzE(0.,0.,beam_pz,beam_E);
double Q = m_target->groundStateMass + m_projectile->groundStateMass - (m_ejectile->groundStateMass + m_residual->groundStateMass + m_ex);
double Q = reactants[0].GetGroundStateMass() + reactants[1].GetGroundStateMass() - (reactants[2].GetGroundStateMass() + reactants[3].GetGroundStateMass() + m_ex);
double Ethresh = -Q*(reactants[2].GetGroundStateMass()+reactants[3].GetGroundStateMass())/(reactants[2].GetGroundStateMass() + reactants[3].GetGroundStateMass() - reactants[1].GetGroundStateMass());
if(m_bke < Ethresh) {
double Ethresh = -Q*(m_ejectile->groundStateMass + m_residual->groundStateMass) /
(m_ejectile->groundStateMass + m_residual->groundStateMass - m_projectile->groundStateMass);
if(m_bke < Ethresh)
throw EnergyThresholdException();
}
auto parent = reactants[0] + reactants[1];
double boost2lab[3];
double boost2cm[3];
const double* boost = parent.GetBoost();
for(int i=0; i<3; i++) {
boost2lab[i] = boost[i];
boost2cm[i] = boost[i]*(-1.0);
}
parent.ApplyBoost(boost2cm);
double ejectE_cm = (std::pow(reactants[2].GetGroundStateMass(), 2.0) - std::pow(reactants[3].GetGroundStateMass() + m_ex, 2.0) + std::pow(parent.GetE(),2.0))/(2.0*parent.GetE());
double ejectP_cm = std::sqrt(ejectE_cm*ejectE_cm - std::pow(reactants[2].GetGroundStateMass(), 2.0));
reactants[2].SetVectorSpherical(m_theta, m_phi, ejectP_cm, ejectE_cm);
reactants[2].ApplyBoost(boost2lab);
reactants[3] = reactants[0] + reactants[1] - reactants[2];
ROOT::Math::PxPyPzEVector parent = m_target->vec4 + m_projectile->vec4;
ROOT::Math::Boost boost(parent.BoostToCM());
parent = boost*parent;
double ejectE_cm = (std::pow(m_ejectile->groundStateMass, 2.0) -
std::pow(m_residual->groundStateMass + m_ex, 2.0) + std::pow(parent.E(),2.0))/
(2.0*parent.E());
double ejectP_cm = std::sqrt(ejectE_cm*ejectE_cm - std::pow(m_ejectile->groundStateMass, 2.0));
m_ejectile->SetVec4Spherical(m_theta, m_phi, ejectP_cm, ejectE_cm);
m_ejectile->vec4 = boost.Inverse() * m_ejectile->vec4;
m_residual->vec4 = m_target->vec4 + m_projectile->vec4 - m_ejectile->vec4;
double ejectKE = reactants[2].GetKE();
double ejectP = reactants[2].GetP();
double ejectE = reactants[2].GetE();
double ejectKE = m_ejectile->GetKE();
double ejectP = m_ejectile->vec4.P();
double ejectE = m_ejectile->vec4.E();
//energy loss for ejectile (after reaction!)
ejectKE -= target->GetEjectileEnergyLoss(reactants[2].GetZ(), reactants[2].GetA(), ejectKE, rxnLayer, reactants[2].GetTheta());
ejectP = std::sqrt(ejectKE*(ejectKE + 2.0 * reactants[2].GetGroundStateMass()));
ejectE = ejectKE + reactants[2].GetGroundStateMass();
reactants[2].SetVectorSpherical(reactants[2].GetTheta(), reactants[2].GetPhi(), ejectP, ejectE);
ejectKE -= m_layeredTarget->GetEjectileEnergyLoss(m_ejectile->Z, m_ejectile->A, ejectKE, m_rxnLayer, m_ejectile->vec4.Theta());
ejectP = std::sqrt(ejectKE*(ejectKE + 2.0 * m_ejectile->groundStateMass));
ejectE = ejectKE + m_ejectile->groundStateMass;
m_ejectile->SetVec4Spherical(m_ejectile->vec4.Theta(), m_ejectile->vec4.Phi(), ejectP, ejectE);
//if on, get eloss for residual (after reaction!)
if(resid_elossFlag) {
double residKE = reactants[3].GetKE() - target->GetEjectileEnergyLoss(reactants[3].GetZ(), reactants[3].GetA(), reactants[3].GetKE(), rxnLayer, reactants[3].GetTheta());
double residP = std::sqrt(residKE*(residKE + 2.0*reactants[3].GetInvMass()));
double residE = residKE + reactants[3].GetInvMass();
reactants[3].SetVectorSpherical(reactants[3].GetTheta(), reactants[3].GetPhi(), residP, residE);
if(m_isResidEloss)
{
double residKE = m_residual->GetKE() -
m_layeredTarget->GetEjectileEnergyLoss(m_residual->Z, m_residual->A, m_residual->GetKE(), m_rxnLayer, m_residual->vec4.Theta());
double residP = std::sqrt(residKE*(residKE + 2.0*m_residual->vec4.M()));
double residE = residKE + m_residual->vec4.M();
m_residual->SetVec4Spherical(m_residual->vec4.Theta(), m_residual->vec4.Phi(), residP, residE);
}
}
void Reaction::CalculateReaction() {
switch(m_eject_theta_type) {
case center_of_mass:
{
CalculateReactionThetaCM();
break;
}
case lab:
{
CalculateReactionThetaLab();
break;
}
void Reaction::CalculateReaction()
{
switch(m_ejectThetaType)
{
case RxnThetaType::CenterOfMass: CalculateReactionThetaCM(); break;
case RxnThetaType::Lab: CalculateReactionThetaLab(); break;
case RxnThetaType::None: CalculateReactionThetaCM(); break; //default behavior
}
}
//Calculate in CM, where decay is isotropic
void Reaction::CalculateDecay() {
double Q = reactants[0].GetInvMass() - reactants[2].GetGroundStateMass() - reactants[3].GetGroundStateMass();
if(Q < 0) {
void Reaction::CalculateDecay()
{
double Q = m_target->vec4.M() - m_ejectile->groundStateMass - m_residual->groundStateMass;
if(Q < 0)
throw QValueException();
}
const double* boost = reactants[0].GetBoost();
double boost2cm[3];
double boost2lab[3];
for(int i=0; i<3; i++) {
boost2lab[i] = boost[i];
boost2cm[i] = boost[i]*(-1.0);
}
ROOT::Math::Boost boost(m_target->vec4.BoostToCM());
m_target->vec4 = boost*m_target->vec4;
double ejectE_cm = (m_ejectile->groundStateMass*m_ejectile->groundStateMass -
m_residual->groundStateMass*m_residual->groundStateMass + m_target->vec4.E()*m_target->vec4.E()) /
(2.0*m_target->vec4.E());
double ejectP_cm = std::sqrt(ejectE_cm*ejectE_cm - m_ejectile->groundStateMass*m_ejectile->groundStateMass);
reactants[0].ApplyBoost(&(boost2cm[0]));
double ejectE_cm = (reactants[2].GetGroundStateMass()*reactants[2].GetGroundStateMass() - reactants[3].GetGroundStateMass()*reactants[3].GetGroundStateMass() + reactants[0].GetE()*reactants[0].GetE())/
(2.0*reactants[0].GetE());
double ejectP_cm = std::sqrt(ejectE_cm*ejectE_cm - reactants[2].GetGroundStateMass()*reactants[2].GetGroundStateMass());
m_ejectile->SetVec4Spherical(m_theta, m_phi, ejectP_cm, ejectE_cm);
m_ejectile->thetaCM = m_theta;
reactants[2].SetVectorSpherical(m_theta, m_phi, ejectP_cm, ejectE_cm);
reactants[2].SetThetaCM(m_theta);
m_target->vec4 = boost.Inverse() * m_target->vec4;
m_ejectile->vec4 = boost.Inverse() * m_ejectile->vec4;
reactants[0].ApplyBoost(boost2lab);
reactants[2].ApplyBoost(boost2lab);
reactants[3] = reactants[0] - reactants[2];
m_residual->vec4 = m_target->vec4 - m_ejectile->vec4;
//energy loss for the *light* break up nucleus
double ejectKE = reactants[2].GetKE() - target->GetEjectileEnergyLoss(reactants[2].GetZ(), reactants[2].GetA(), reactants[2].GetKE(), rxnLayer, reactants[2].GetTheta());
double ejectP = std::sqrt(ejectKE*(ejectKE + 2.0*reactants[2].GetGroundStateMass()));
double ejectE = ejectKE + reactants[2].GetGroundStateMass();
reactants[2].SetVectorSpherical(reactants[2].GetTheta(), reactants[2].GetPhi(), ejectP, ejectE);
double ejectKE = m_ejectile->GetKE() -
m_layeredTarget->GetEjectileEnergyLoss(m_ejectile->Z, m_ejectile->A, m_ejectile->GetKE(), m_rxnLayer, m_ejectile->vec4.Theta());
double ejectP = std::sqrt(ejectKE*(ejectKE + 2.0*m_ejectile->groundStateMass));
double ejectE = ejectKE + m_ejectile->groundStateMass;
m_ejectile->SetVec4Spherical(m_ejectile->vec4.Theta(), m_ejectile->vec4.Phi(), ejectP, ejectE);
//if on, get eloss for *heavy* break up nucleus
if(resid_elossFlag) {
double residKE = reactants[3].GetKE() - target->GetEjectileEnergyLoss(reactants[3].GetZ(), reactants[3].GetA(), reactants[3].GetKE(), rxnLayer, reactants[3].GetTheta());
double residP = std::sqrt(residKE*(residKE + 2.0*reactants[3].GetInvMass()));
double residE = residKE + reactants[3].GetInvMass();
reactants[3].SetVectorSpherical(reactants[3].GetTheta(), reactants[3].GetPhi(), residP, residE);
if(m_isResidEloss)
{
double residKE = m_residual->GetKE() -
m_layeredTarget->GetEjectileEnergyLoss(m_residual->Z, m_residual->A, m_residual->GetKE(), m_rxnLayer, m_residual->vec4.Theta());
double residP = std::sqrt(residKE*(residKE + 2.0*m_residual->vec4.M()));
double residE = residKE + m_residual->vec4.M();
m_residual->SetVec4Spherical(m_residual->vec4.Theta(), m_residual->vec4.Phi(), residP, residE);
}
}

72
src/Mask/Reaction.h Normal file
View File

@ -0,0 +1,72 @@
/*
Reaction.h
Reaction is a class which implements either a decay or scattering reaction. As such it requires either
3 (decay) or 4 (scattering) nuclei to perform any calcualtions. I also links together the target, which provides
energy loss calculations, with the kinematics. Note that Reaction does not own the LayeredTarget.
--GWM Jan. 2021
*/
#ifndef REACTION_H
#define REACTION_H
#include "Nucleus.h"
#include "LayeredTarget.h"
#include "RxnType.h"
namespace Mask {
class Reaction
{
public:
Reaction();
Reaction(Nucleus* target, Nucleus* projectile, Nucleus* ejectile, Nucleus* residual);
~Reaction();
bool Calculate(); //do sim
void BindNuclei(Nucleus* target, Nucleus* projectile, Nucleus* ejectile, Nucleus* residual);
void SetBeamKE(double bke);
void SetEjectileThetaType(RxnThetaType type);
void SetLayeredTarget(LayeredTarget* targ) { m_layeredTarget = targ; };
void SetPolarRxnAngle(double theta) { m_theta = theta; };
void SetAzimRxnAngle(double phi) { m_phi = phi; };
void SetExcitation(double ex) { m_ex = ex; };
void BindTarget(Nucleus* nuc) { m_target = nuc; };
void BindProjectile(Nucleus* nuc) { m_projectile = nuc; };
void BindEjectile(Nucleus* nuc) { m_ejectile = nuc; };
void BindResidual(Nucleus* nuc) { m_residual = nuc; };
void SetRxnLayer(std::size_t layer) { m_rxnLayer = layer; };
void SetResidualEnergyLoss(bool isEloss) { m_isResidEloss = isEloss; };
bool IsDecay() const { return m_isDecay; };
std::size_t GetRxnLayer() const { return m_rxnLayer; };
private:
void CalculateDecay(); //target -> light_decay (eject) + heavy_decay(resid)
void CalculateReaction(); //target + project -> eject + resid
void CalculateReactionThetaLab();
void CalculateReactionThetaCM();
//Reactants -> NOT OWNED BY RXN
Nucleus* m_target;
Nucleus* m_projectile;
Nucleus* m_ejectile;
Nucleus* m_residual;
LayeredTarget* m_layeredTarget; //not owned by Reaction
double m_bke, m_theta, m_phi, m_ex;
int m_rxnLayer;
RxnThetaType m_ejectThetaType;
bool m_isDecay, m_isInit, m_isResidEloss;
};
}
#endif

View File

@ -1,24 +1,50 @@
#include "ReactionSystem.h"
#include "RxnType.h"
#include "KinematicsExceptions.h"
#include "LegendrePoly.h"
#include "DecaySystem.h"
#include "OneStepSystem.h"
#include "TwoStepSystem.h"
#include "ThreeStepSystem.h"
namespace Mask {
ReactionSystem::ReactionSystem() :
m_beamDist(nullptr), m_theta1Range(nullptr), m_phi1Range(nullptr), m_exDist(nullptr), target_set_flag(false),
rxnLayer(0), m_sys_equation("")
m_beamDist(nullptr), m_theta1Range(nullptr), m_phi1Range(nullptr), m_exDist(nullptr), m_isTargetSet(false),
m_rxnLayer(0), m_sysEquation("")
{
}
ReactionSystem::~ReactionSystem() {
ReactionSystem::~ReactionSystem()
{
delete m_beamDist;
delete m_theta1Range;
delete m_phi1Range;
delete m_exDist;
}
void ReactionSystem::AddTargetLayer(std::vector<int>& zt, std::vector<int>& at, std::vector<int>& stoich, double thickness) {
target.AddLayer(zt, at, stoich, thickness);
void ReactionSystem::AddTargetLayer(const std::vector<int>& zt, const std::vector<int>& at, const std::vector<int>& stoich, double thickness)
{
m_target.AddLayer(zt, at, stoich, thickness);
}
ReactionSystem* CreateSystem(const std::vector<int>& z, const std::vector<int>& a)
{
if(z.size() != a.size())
{
std::cerr<<"Size of Z list does not equal size of A list!"<<std::endl;
return nullptr;
}
switch(a.size())
{
case RxnSize::DecaySize: return new DecaySystem(z, a);
case RxnSize::OneStepSize: return new OneStepSystem(z, a);
case RxnSize::TwoStepSize: return new TwoStepSystem(z, a);
case RxnSize::ThreeStepSize: return new ThreeStepSystem(z, a);
}
return nullptr;
}
}

View File

@ -11,66 +11,76 @@
#include "Reaction.h"
#include "KinematicsExceptions.h"
#include "RxnType.h"
#include <vector>
#include <random>
namespace Mask {
class ReactionSystem {
class ReactionSystem
{
public:
ReactionSystem();
virtual ~ReactionSystem();
virtual bool SetNuclei(std::vector<int>& z, std::vector<int>& a) = 0;
virtual bool SetNuclei(const std::vector<int>& z, const std::vector<int>& a) = 0;
virtual void RunSystem() = 0;
virtual const std::vector<Nucleus>& GetNuclei() = 0;
virtual std::vector<Nucleus>* GetNuclei() = 0;
virtual void SetReactionThetaType(RxnThetaType type) {}
virtual void SetDecay1Distribution(const std::string& filename) {}
virtual void SetDecay2Distribution(const std::string& filename) {}
void AddTargetLayer(std::vector<int>& zt, std::vector<int>& at, std::vector<int>& stoich, double thickness);
void AddTargetLayer(const std::vector<int>& zt, const std::vector<int>& at, const std::vector<int>& stoich, double thickness);
/*Set sampling parameters*/
inline void SetBeamDistro(double mean, double sigma) {
void SetBeamDistro(double mean, double sigma)
{
if(m_beamDist)
delete m_beamDist;
m_beamDist = new std::normal_distribution<double>(mean, sigma);
}
inline void SetTheta1Range(double min, double max) {
void SetTheta1Range(double min, double max)
{
if(m_theta1Range)
delete m_theta1Range;
m_theta1Range = new std::uniform_real_distribution<double>(std::cos(min*deg2rad), std::cos(max*deg2rad));
m_theta1Range = new std::uniform_real_distribution<double>(std::cos(min*s_deg2rad), std::cos(max*s_deg2rad));
}
inline void SetPhi1Range(double min, double max) {
void SetPhi1Range(double min, double max)
{
if(m_phi1Range)
delete m_phi1Range;
m_phi1Range = new std::uniform_real_distribution<double>(min*deg2rad, max*deg2rad);
m_phi1Range = new std::uniform_real_distribution<double>(min*s_deg2rad, max*s_deg2rad);
}
inline void SetExcitationDistro(double mean, double sigma) {
void SetExcitationDistro(double mean, double sigma)
{
if(m_exDist)
delete m_exDist;
m_exDist = new std::normal_distribution<double>(mean, sigma);
}
inline const std::string& GetSystemEquation() const { return m_sys_equation; }
const std::string& GetSystemEquation() const { return m_sysEquation; }
protected:
virtual void LinkTarget() = 0;
virtual void SetSystemEquation() = 0;
LayeredTarget target;
LayeredTarget m_target;
//Sampling information
std::normal_distribution<double> *m_beamDist, *m_exDist;
std::uniform_real_distribution<double> *m_theta1Range, *m_phi1Range;
bool target_set_flag, gen_set_flag;
int rxnLayer;
std::string m_sys_equation;
std::vector<Nucleus> nuclei;
static constexpr double deg2rad = M_PI/180.0;
bool m_isTargetSet;
std::size_t m_rxnLayer;
std::string m_sysEquation;
std::vector<Nucleus> m_nuclei;
static constexpr double s_deg2rad = M_PI/180.0;
};
ReactionSystem* CreateSystem(const std::vector<int>& z, const std::vector<int>& a);
}
#endif

View File

@ -1,71 +0,0 @@
/*
Classes which define rotations about the x, y, and z axes. Using these,
any arbitrary orientation can be described. Methods implemented for vector multiplication
as well as generating the inverse of the rotation.
*/
#include "Rotation.h"
namespace Mask {
XRotation::XRotation() :
m_angle(0)
{
GenerateMatrix();
}
XRotation::XRotation(double angle) :
m_angle(angle)
{
GenerateMatrix();
}
XRotation::~XRotation() {}
void XRotation::GenerateMatrix() {
m_matrix[0][0] = 1.0; m_matrix[0][1] = 0.0; m_matrix[0][2] = 0.0;
m_matrix[1][0] = 0.0; m_matrix[1][1] = std::cos(m_angle); m_matrix[1][2] = -std::sin(m_angle);
m_matrix[2][0] = 0.0; m_matrix[2][1] = std::sin(m_angle); m_matrix[2][2] = std::cos(m_angle);
}
YRotation::YRotation() :
m_angle(0)
{
GenerateMatrix();
}
YRotation::YRotation(double angle) :
m_angle(angle)
{
GenerateMatrix();
}
YRotation::~YRotation() {}
void YRotation::GenerateMatrix() {
m_matrix[0][0] = std::cos(m_angle); m_matrix[0][1] = 0.0; m_matrix[0][2] = -std::sin(m_angle);
m_matrix[1][0] = 0.0; m_matrix[1][1] = 1.0; m_matrix[1][2] = 0.0;
m_matrix[2][0] = std::sin(m_angle); m_matrix[2][1] = 0.0; m_matrix[2][2] = std::cos(m_angle);
}
ZRotation::ZRotation() :
m_angle(0)
{
GenerateMatrix();
}
ZRotation::ZRotation(double angle) :
m_angle(angle)
{
GenerateMatrix();
}
ZRotation::~ZRotation() {}
void ZRotation::GenerateMatrix() {
m_matrix[0][0] = std::cos(m_angle); m_matrix[0][1] = -std::sin(m_angle); m_matrix[0][2] = 0.0;
m_matrix[1][0] = std::sin(m_angle); m_matrix[1][1] = std::cos(m_angle); m_matrix[1][2] = 0.0;
m_matrix[2][0] = 0.0; m_matrix[2][1] = 0.0; m_matrix[2][2] = 1.0;
}
};

View File

@ -14,6 +14,21 @@ namespace Mask {
None=4
};
enum class RxnThetaType
{
CenterOfMass,
Lab,
None
};
enum RxnSize
{
DecaySize = 2,
OneStepSize = 3,
TwoStepSize = 4,
ThreeStepSize = 5
};
static RxnType GetRxnTypeFromString(const std::string& type_str)
{
if (type_str == "PureDecay")
@ -52,6 +67,21 @@ namespace Mask {
return static_cast<uint32_t>(type);
}
static RxnThetaType StringToRxnThetaType(const std::string& type)
{
if(type == "CenterOfMass")
{
return RxnThetaType::CenterOfMass;
}
else if(type == "Lab")
{
return RxnThetaType::Lab;
}
else
{
return RxnThetaType::None;
}
}
}
#endif

View File

@ -7,25 +7,34 @@
*/
#include "Stopwatch.h"
Stopwatch::Stopwatch() {
start_time = Clock::now();
stop_time = start_time;
}
namespace Mask {
Stopwatch::~Stopwatch() {}
Stopwatch::Stopwatch()
{
start_time = Clock::now();
stop_time = start_time;
}
void Stopwatch::Start() {
start_time = Clock::now();
}
Stopwatch::~Stopwatch() {}
void Stopwatch::Stop() {
stop_time = Clock::now();
}
void Stopwatch::Start()
{
start_time = Clock::now();
}
double Stopwatch::GetElapsedSeconds() {
return std::chrono::duration_cast<std::chrono::duration<double>>(stop_time-start_time).count();
}
void Stopwatch::Stop()
{
stop_time = Clock::now();
}
double Stopwatch::GetElapsedSeconds()
{
return std::chrono::duration_cast<std::chrono::duration<double>>(stop_time-start_time).count();
}
double Stopwatch::GetElapsedMilliseconds()
{
return std::chrono::duration_cast<std::chrono::duration<double>>(stop_time-start_time).count()*1000.0;
}
double Stopwatch::GetElapsedMilliseconds() {
return std::chrono::duration_cast<std::chrono::duration<double>>(stop_time-start_time).count()*1000.0;
}

32
src/Mask/Stopwatch.h Normal file
View File

@ -0,0 +1,32 @@
/*
Stopwatch.h
Simple class designed to provide timing info on parts of the process.
Only for use in development.
Written by G.W. McCann Oct. 2020
*/
#ifndef STOPWATCH_H
#define STOPWATCH_H
#include <chrono>
namespace Mask {
class Stopwatch
{
public:
Stopwatch();
~Stopwatch();
void Start();
void Stop();
double GetElapsedSeconds();
double GetElapsedMilliseconds();
private:
using Time = std::chrono::high_resolution_clock::time_point;
using Clock = std::chrono::high_resolution_clock;
Time start_time, stop_time;
};
}
#endif

View File

@ -16,45 +16,50 @@ Written by G.W. McCann Aug. 2020
namespace Mask {
/*Targets must be of known thickness*/
Target::Target(double thick) {
thickness = thick;
thickness_gcm2 = thickness*1.0e-6;
Target::Target(const std::vector<int>& z, const std::vector<int>& a, const std::vector<int>& stoich, double thick) :
m_thickness(thick), m_thickness_gcm2(thick*1.0e-6)
{
Init(z, a, stoich);
}
Target::~Target() {}
/*Set target elements of given Z, A, S*/
void Target::SetElements(std::vector<int>& z, std::vector<int>& a, std::vector<int>& stoich) {
Z = z;
A = a;
Stoich = stoich;
void Target::Init(const std::vector<int>& z, const std::vector<int>& a, const std::vector<int>& stoich)
{
m_Z = z;
m_A = a;
m_stoich = stoich;
MassLookup& masses = MassLookup::GetInstance();
eloss.SetTargetComponents(Z, A, Stoich);
for(size_t i=0; i<Z.size(); i++)
for(size_t i=0; i<m_Z.size(); i++)
{
target_material.add_element(masses.FindMassU(Z[i], A[i]), Z[i], Stoich[i]);
m_material.add_element(masses.FindMassU(m_Z[i], m_A[i]), m_Z[i], m_stoich[i]);
}
}
/*Element verification*/
bool Target::ContainsElement(int z, int a) {
for(unsigned int i=0; i<Z.size(); i++)
if( z == Z[i] && a == A[i])
bool Target::ContainsElement(int z, int a)
{
for(std::size_t i=0; i<m_Z.size(); i++)
{
if( z == m_Z[i] && a == m_A[i])
return true;
}
return false;
}
/*Calculates energy loss for travelling all the way through the target*/
double Target::GetEnergyLossTotal(int zp, int ap, double startEnergy, double theta) {
double Target::GetEnergyLossTotal(int zp, int ap, double startEnergy, double theta)
{
if(theta == M_PI/2.)
return startEnergy;
else if (theta > M_PI/2.)
theta = M_PI - theta;
catima::Projectile proj(MassLookup::GetInstance().FindMassU(zp, ap), zp, 0.0, 0.0);
proj.T = startEnergy/proj.A;
target_material.thickness(thickness_gcm2/fabs(cos(theta)));
return catima::integrate_energyloss(proj, target_material);
//return eloss.GetEnergyLoss(zp, ap, startEnergy, thickness/fabs(cos(theta)));
m_material.thickness(m_thickness_gcm2/fabs(cos(theta)));
return catima::integrate_energyloss(proj, m_material);
}
/*Calculates the energy loss for traveling some fraction through the target*/
@ -67,13 +72,13 @@ namespace Mask {
catima::Projectile proj(MassLookup::GetInstance().FindMassU(zp, ap), zp, 0.0, 0.0);
proj.T = finalEnergy/proj.A;
target_material.thickness(thickness_gcm2*percent_depth/fabs(cos(theta)));
return catima::integrate_energyloss(proj, target_material);
//return eloss.GetEnergyLoss(zp, ap, finalEnergy, thickness*percent_depth/(std::fabs(std::cos(theta))));
m_material.thickness(m_thickness_gcm2*percent_depth/fabs(cos(theta)));
return catima::integrate_energyloss(proj, m_material);
}
/*Calculates reverse energy loss for travelling all the way through the target*/
double Target::GetReverseEnergyLossTotal(int zp, int ap, double finalEnergy, double theta) {
double Target::GetReverseEnergyLossTotal(int zp, int ap, double finalEnergy, double theta)
{
if(theta == M_PI/2.)
return finalEnergy;
else if (theta > M_PI/2.)
@ -81,9 +86,8 @@ namespace Mask {
catima::Projectile proj(MassLookup::GetInstance().FindMassU(zp, ap), zp, 0.0, 0.0);
proj.T = finalEnergy/proj.A;
target_material.thickness(thickness_gcm2/fabs(cos(theta)));
return catima::reverse_integrate_energyloss(proj, target_material);
//return eloss.GetReverseEnergyLoss(zp, ap, finalEnergy, thickness/fabs(cos(theta)));
m_material.thickness(m_thickness_gcm2/fabs(cos(theta)));
return catima::reverse_integrate_energyloss(proj, m_material);
}
/*Calculates the reverse energy loss for traveling some fraction through the target*/
@ -95,9 +99,8 @@ namespace Mask {
theta = M_PI-theta;
catima::Projectile proj(MassLookup::GetInstance().FindMassU(zp, ap), zp, 0.0, 0.0);
proj.T = finalEnergy/proj.A;
target_material.thickness(thickness_gcm2*percent_depth/fabs(cos(theta)));
return catima::reverse_integrate_energyloss(proj, target_material);
//return eloss.GetReverseEnergyLoss(zp, ap, finalEnergy, thickness*percent_depth/(std::fabs(std::cos(theta))));
m_material.thickness(m_thickness_gcm2*percent_depth/fabs(cos(theta)));
return catima::reverse_integrate_energyloss(proj, m_material);
}
}

View File

@ -16,7 +16,6 @@ Written by G.W. McCann Aug. 2020
#include <string>
#include <vector>
#include <cmath>
#include "EnergyLoss.h"
#include "catima/gwm_integrators.h"
#include "MassLookup.h"
@ -25,26 +24,26 @@ namespace Mask {
class Target {
public:
Target(double thick);
Target(const std::vector<int>& z, const std::vector<int>& a, const std::vector<int>& stoich, double thick);
~Target();
void SetElements(std::vector<int>& z, std::vector<int>& a, std::vector<int>& stoich);
bool ContainsElement(int z, int a);
double GetEnergyLossTotal(int zp, int ap, double startEnergy, double angle);
double GetReverseEnergyLossTotal(int zp, int ap, double finalEnergy, double angle);
double GetEnergyLossFractionalDepth(int zp, int ap, double startEnergy, double angle, double percent_depth);
double GetReverseEnergyLossFractionalDepth(int zp, int ap, double finalEnergy, double angle, double percent_depth);
inline const double& GetThickness() { return thickness; }
inline int GetNumberOfElements() { return Z.size(); }
inline int GetElementZ(int index) { return Z[index]; }
inline int GetElementA(int index) { return A[index]; }
inline int GetElementStoich(int index) { return Stoich[index]; }
inline const double& GetThickness() { return m_thickness; }
inline int GetNumberOfElements() { return m_Z.size(); }
inline int GetElementZ(int index) { return m_Z[index]; }
inline int GetElementA(int index) { return m_A[index]; }
inline int GetElementStoich(int index) { return m_stoich[index]; }
private:
EnergyLoss eloss;
catima::Material target_material;
double thickness;
double thickness_gcm2;
std::vector<int> Z, A, Stoich;
void Init(const std::vector<int>& z, const std::vector<int>& a, const std::vector<int>& stoich);
catima::Material m_material;
double m_thickness;
double m_thickness_gcm2;
std::vector<int> m_Z, m_A, m_stoich;
};

View File

@ -7,133 +7,131 @@ namespace Mask {
ThreeStepSystem::ThreeStepSystem() :
ReactionSystem(), m_phi2Range(0, 2.0*M_PI)
{
nuclei.resize(8);
m_nuclei.resize(8);
}
ThreeStepSystem::ThreeStepSystem(std::vector<int>& z, std::vector<int>& a) :
ThreeStepSystem::ThreeStepSystem(const std::vector<int>& z, const std::vector<int>& a) :
ReactionSystem(), m_phi2Range(0, 2.0*M_PI)
{
nuclei.resize(8);
m_nuclei.resize(8);
SetNuclei(z, a);
}
ThreeStepSystem::~ThreeStepSystem() {}
bool ThreeStepSystem::SetNuclei(std::vector<int>&z, std::vector<int>& a) {
if(z.size() != a.size() || z.size() < 5) {
bool ThreeStepSystem::SetNuclei(const std::vector<int>& z, const std::vector<int>& a)
{
if(z.size() != a.size() || z.size() < 5)
return false;
}
int zr = z[0] + z[1] - z[2];
int zb2 = zr - z[3];
int zb4 = zb2 - z[4];
int ar = a[0] + a[1] - a[2];
int ab2 = ar - a[3];
int ab4 = ab2 - a[4];
m_nuclei[0] = CreateNucleus(z[0], a[0]); //target
m_nuclei[1] = CreateNucleus(z[1], a[1]); //projectile
m_nuclei[2] = CreateNucleus(z[2], a[2]); //ejectile
m_nuclei[3] = CreateNucleus(zr, ar); //residual
m_nuclei[4] = CreateNucleus(z[3], a[3]); //breakup1
m_nuclei[5] = CreateNucleus(zb2, ab2); //breakup2
m_nuclei[5] = CreateNucleus(z[4], a[4]); //breakup3
m_nuclei[5] = CreateNucleus(zb4, ab4); //breakup4
m_step1.BindNuclei(&(m_nuclei[0]), &(m_nuclei[1]), &(m_nuclei[2]), &(m_nuclei[3]));
m_step2.BindNuclei(&(m_nuclei[3]), nullptr, &(m_nuclei[4]), &(m_nuclei[5]));
m_step3.BindNuclei(&(m_nuclei[5]), nullptr, &(m_nuclei[6]), &(m_nuclei[7]));
step1.SetNuclei(z[0], a[0], z[1], a[1], z[2], a[2]);
step2.SetNuclei(zr, ar, 0, 0, z[3], a[3]);
step3.SetNuclei(zb2, ab2, 0, 0, z[4], a[4]);
SetSystemEquation();
return true;
}
const std::vector<Nucleus>& ThreeStepSystem::GetNuclei()
std::vector<Nucleus>* ThreeStepSystem::GetNuclei()
{
nuclei[0] = step1.GetTarget();
nuclei[1] = step1.GetProjectile();
nuclei[2] = step1.GetEjectile();
nuclei[3] = step1.GetResidual();
nuclei[4] = step2.GetEjectile();
nuclei[5] = step2.GetResidual();
nuclei[6] = step3.GetEjectile();
nuclei[7] = step3.GetResidual();
return nuclei;
return &m_nuclei;
}
void ThreeStepSystem::LinkTarget() {
step1.SetLayeredTarget(&target);
step2.SetLayeredTarget(&target);
step3.SetLayeredTarget(&target);
void ThreeStepSystem::LinkTarget()
{
m_step1.SetLayeredTarget(&m_target);
m_step2.SetLayeredTarget(&m_target);
m_step3.SetLayeredTarget(&m_target);
rxnLayer = target.FindLayerContaining(step1.GetTarget().GetZ(), step1.GetTarget().GetA());
if(rxnLayer != -1) {
step1.SetRxnLayer(rxnLayer);
step2.SetRxnLayer(rxnLayer);
step3.SetRxnLayer(rxnLayer);
target_set_flag = true;
} else {
m_rxnLayer = m_target.FindLayerContaining(m_nuclei[0].Z, m_nuclei[0].A);
if(m_rxnLayer != m_target.GetNumberOfLayers())
{
m_step1.SetRxnLayer(m_rxnLayer);
m_step2.SetRxnLayer(m_rxnLayer);
m_step3.SetRxnLayer(m_rxnLayer);
m_isTargetSet = true;
} else
throw ReactionLayerException();
}
}
void ThreeStepSystem::SetSystemEquation() {
m_sys_equation = step1.GetTarget().GetIsotopicSymbol();
m_sys_equation += "(";
m_sys_equation += step1.GetProjectile().GetIsotopicSymbol();
m_sys_equation += ", ";
m_sys_equation += step1.GetEjectile().GetIsotopicSymbol();
m_sys_equation += ")";
m_sys_equation += step1.GetResidual().GetIsotopicSymbol();
m_sys_equation += "-> ";
m_sys_equation += step2.GetEjectile().GetIsotopicSymbol();
m_sys_equation += " + ";
m_sys_equation += step2.GetResidual().GetIsotopicSymbol();
m_sys_equation += "-> ";
m_sys_equation += step3.GetEjectile().GetIsotopicSymbol();
m_sys_equation += " + ";
m_sys_equation += step3.GetResidual().GetIsotopicSymbol();
void ThreeStepSystem::SetSystemEquation()
{
std::stringstream stream;
stream << m_nuclei[0].isotopicSymbol << "("
<< m_nuclei[1].isotopicSymbol << ", "
<< m_nuclei[2].isotopicSymbol << ")"
<< m_nuclei[3].isotopicSymbol << "->"
<< m_nuclei[4].isotopicSymbol << "+"
<< m_nuclei[5].isotopicSymbol << "->"
<< m_nuclei[6].isotopicSymbol << "+"
<< m_nuclei[7].isotopicSymbol;
m_sysEquation = stream.str();
}
void ThreeStepSystem::RunSystem() {
//Link up the target if it hasn't been done yet
if(!target_set_flag) {
if(!m_isTargetSet)
LinkTarget();
}
//Sample parameters
double bke = (*m_beamDist)(RandomGenerator::GetInstance().GetGenerator());
double rxnTheta = acos((*m_theta1Range)(RandomGenerator::GetInstance().GetGenerator()));
double rxnPhi = (*m_phi1Range)(RandomGenerator::GetInstance().GetGenerator());
double decay1costheta = decay1dist.GetRandomCosTheta();
double decay1costheta = m_step2Distribution.GetRandomCosTheta();
double decay1Theta = std::acos(decay1costheta);
double decay1Phi = m_phi2Range(RandomGenerator::GetInstance().GetGenerator());
double decay2costheta = decay2dist.GetRandomCosTheta();
double decay2costheta = m_step3Distribution.GetRandomCosTheta();
double decay2Theta = std::acos(decay2costheta);
double decay2Phi = m_phi2Range(RandomGenerator::GetInstance().GetGenerator());
double residEx = (*m_exDist)(RandomGenerator::GetInstance().GetGenerator());
step1.SetBeamKE(bke);
step1.SetPolarRxnAngle(rxnTheta);
step1.SetAzimRxnAngle(rxnPhi);
step1.SetExcitation(residEx);
m_step1.SetBeamKE(bke);
m_step1.SetPolarRxnAngle(rxnTheta);
m_step1.SetAzimRxnAngle(rxnPhi);
m_step1.SetExcitation(residEx);
step2.SetPolarRxnAngle(decay1Theta);
step2.SetAzimRxnAngle(decay1Phi);
m_step2.SetPolarRxnAngle(decay1Theta);
m_step2.SetAzimRxnAngle(decay1Phi);
step3.SetPolarRxnAngle(decay2Theta);
step3.SetAzimRxnAngle(decay2Phi);
m_step3.SetPolarRxnAngle(decay2Theta);
m_step3.SetAzimRxnAngle(decay2Phi);
step1.Calculate();
m_step1.Calculate();
step2.SetTarget(step1.GetResidual());
if(decay1costheta == -10) {
step2.ResetEjectile();
step2.ResetResidual();
step3.ResetTarget();
step3.ResetEjectile();
step3.ResetResidual();
if(decay1costheta == -10)
{
m_nuclei[4].vec4.SetPxPyPzE(0., 0., 0., m_nuclei[4].groundStateMass);
m_nuclei[5].vec4.SetPxPyPzE(0., 0., 0., m_nuclei[5].groundStateMass);
m_nuclei[6].vec4.SetPxPyPzE(0., 0., 0., m_nuclei[6].groundStateMass);
m_nuclei[7].vec4.SetPxPyPzE(0., 0., 0., m_nuclei[7].groundStateMass);
return;
}
step2.Calculate();
m_step2.Calculate();
step3.SetTarget(step2.GetResidual());
if(decay2costheta == -10) {
step3.ResetEjectile();
step3.ResetResidual();
if(decay2costheta == -10)
{
m_nuclei[6].vec4.SetPxPyPzE(0., 0., 0., m_nuclei[6].groundStateMass);
m_nuclei[7].vec4.SetPxPyPzE(0., 0., 0., m_nuclei[7].groundStateMass);
return;
}
step3.TurnOnResidualEloss();
step3.Calculate();
m_step3.SetResidualEnergyLoss(true);
m_step3.Calculate();
}

View File

@ -0,0 +1,42 @@
#ifndef THREESTEPSYSTEM_H
#define THREESTEPSYSTEM_H
#include "ReactionSystem.h"
#include "AngularDistribution.h"
namespace Mask {
class ThreeStepSystem : public ReactionSystem {
public:
ThreeStepSystem();
ThreeStepSystem(const std::vector<int>& z, const std::vector<int>& a);
~ThreeStepSystem();
bool SetNuclei(const std::vector<int>& z, const std::vector<int>& a) override;
void RunSystem() override;
std::vector<Nucleus>* GetNuclei() override;
virtual void SetDecay1Distribution(const std::string& filename) override { m_step2Distribution.ReadDistributionFile(filename); };
virtual void SetDecay2Distribution(const std::string& filename) override { m_step3Distribution.ReadDistributionFile(filename); };
virtual void SetReactionThetaType(RxnThetaType type) override { m_step1.SetEjectileThetaType(type); };
int GetDecay1AngularMomentum() { return m_step2Distribution.GetL(); };
int GetDecay2AngularMomentum(){ return m_step3Distribution.GetL(); };
double GetDecay1BranchingRatio() { return m_step2Distribution.GetBranchingRatio(); };
double GetDecay2BranchingRatio(){ return m_step3Distribution.GetBranchingRatio(); };
protected:
void LinkTarget() override;
void SetSystemEquation() override;
std::uniform_real_distribution<double> m_phi2Range;
Reaction m_step1, m_step2, m_step3;
AngularDistribution m_step2Distribution, m_step3Distribution;
};
}
#endif

View File

@ -2,111 +2,114 @@
#include "RandomGenerator.h"
#include "KinematicsExceptions.h"
#include <sstream>
namespace Mask {
TwoStepSystem::TwoStepSystem() :
ReactionSystem(), m_phi2Range(0, 2.0*M_PI)
{
nuclei.resize(6);
m_nuclei.resize(6);
}
TwoStepSystem::TwoStepSystem(std::vector<int>& z, std::vector<int>& a) :
TwoStepSystem::TwoStepSystem(const std::vector<int>& z, const std::vector<int>& a) :
ReactionSystem(), m_phi2Range(0, 2.0*M_PI)
{
nuclei.resize(6);
m_nuclei.resize(6);
SetNuclei(z, a);
}
TwoStepSystem::~TwoStepSystem() {
TwoStepSystem::~TwoStepSystem() {}
}
bool TwoStepSystem::SetNuclei(std::vector<int>&z, std::vector<int>& a) {
if(z.size() != a.size() || z.size() != 4) {
bool TwoStepSystem::SetNuclei(const std::vector<int>&z, const std::vector<int>& a)
{
if(z.size() != a.size() || z.size() != 4)
return false;
}
int zr = z[0] + z[1] - z[2];
int ar = a[0] + a[1] - a[2];
int zb = zr - z[3];
int ab = ar - a[3];
m_nuclei[0] = CreateNucleus(z[0], a[0]); //target
m_nuclei[1] = CreateNucleus(z[1], a[1]); //projectile
m_nuclei[2] = CreateNucleus(z[2], a[2]); //ejectile
m_nuclei[3] = CreateNucleus(zr, ar); //residual
m_nuclei[4] = CreateNucleus(z[3], a[3]); //breakup1
m_nuclei[5] = CreateNucleus(zb, ab); //breakup2
step1.SetNuclei(z[0], a[0], z[1], a[1], z[2], a[2]);
step2.SetNuclei(zr, ar, 0, 0, z[3], a[3]);
m_step1.BindNuclei(&(m_nuclei[0]), &(m_nuclei[1]), &(m_nuclei[2]), &(m_nuclei[3]));
m_step2.BindNuclei(&(m_nuclei[3]), nullptr, &(m_nuclei[4]), &(m_nuclei[5]));
SetSystemEquation();
return true;
}
const std::vector<Nucleus>& TwoStepSystem::GetNuclei()
std::vector<Nucleus>* TwoStepSystem::GetNuclei()
{
nuclei[0] = step1.GetTarget();
nuclei[1] = step1.GetProjectile();
nuclei[2] = step1.GetEjectile();
nuclei[3] = step1.GetResidual();
nuclei[4] = step2.GetEjectile();
nuclei[5] = step2.GetResidual();
return nuclei;
return &m_nuclei;
}
void TwoStepSystem::LinkTarget() {
step1.SetLayeredTarget(&target);
step2.SetLayeredTarget(&target);
void TwoStepSystem::LinkTarget()
{
m_step1.SetLayeredTarget(&m_target);
m_step2.SetLayeredTarget(&m_target);
rxnLayer = target.FindLayerContaining(step1.GetTarget().GetZ(), step1.GetTarget().GetA());
if(rxnLayer != -1) {
step1.SetRxnLayer(rxnLayer);
step2.SetRxnLayer(rxnLayer);
target_set_flag = true;
} else {
m_rxnLayer = m_target.FindLayerContaining(m_nuclei[0].Z, m_nuclei[0].A);
if(m_rxnLayer != m_target.GetNumberOfLayers())
{
m_step1.SetRxnLayer(m_rxnLayer);
m_step2.SetRxnLayer(m_rxnLayer);
m_isTargetSet = true;
}
else
throw ReactionLayerException();
}
}
void TwoStepSystem::SetSystemEquation() {
m_sys_equation = step1.GetTarget().GetIsotopicSymbol();
m_sys_equation += "(";
m_sys_equation += step1.GetProjectile().GetIsotopicSymbol();
m_sys_equation += ", ";
m_sys_equation += step1.GetEjectile().GetIsotopicSymbol();
m_sys_equation += ")";
m_sys_equation += step1.GetResidual().GetIsotopicSymbol();
m_sys_equation += "-> ";
m_sys_equation += step2.GetEjectile().GetIsotopicSymbol();
m_sys_equation += "+";
m_sys_equation += step2.GetResidual().GetIsotopicSymbol();
void TwoStepSystem::SetSystemEquation()
{
std::stringstream stream;
stream << m_nuclei[0].isotopicSymbol << "("
<< m_nuclei[1].isotopicSymbol << ", "
<< m_nuclei[2].isotopicSymbol << ")"
<< m_nuclei[3].isotopicSymbol << "->"
<< m_nuclei[4].isotopicSymbol << "+"
<< m_nuclei[5].isotopicSymbol;
m_sysEquation = stream.str();
}
void TwoStepSystem::RunSystem() {
void TwoStepSystem::RunSystem()
{
//Link up the target if it hasn't been done yet
if(!target_set_flag) {
if(!m_isTargetSet)
LinkTarget();
}
//Sample parameters
double bke = (*m_beamDist)(RandomGenerator::GetInstance().GetGenerator());
double rxnTheta = acos((*m_theta1Range)(RandomGenerator::GetInstance().GetGenerator()));
double rxnPhi = (*m_phi1Range)(RandomGenerator::GetInstance().GetGenerator());
double decay1costheta = decay1dist.GetRandomCosTheta();
double decay1costheta = m_step2Distribution.GetRandomCosTheta();
double decay1Theta = std::acos(decay1costheta);
double decay1Phi = m_phi2Range(RandomGenerator::GetInstance().GetGenerator());
double residEx = (*m_exDist)(RandomGenerator::GetInstance().GetGenerator());
step1.SetBeamKE(bke);
step1.SetPolarRxnAngle(rxnTheta);
step1.SetAzimRxnAngle(rxnPhi);
step1.SetExcitation(residEx);
m_step1.SetBeamKE(bke);
m_step1.SetPolarRxnAngle(rxnTheta);
m_step1.SetAzimRxnAngle(rxnPhi);
m_step1.SetExcitation(residEx);
step2.SetPolarRxnAngle(decay1Theta);
step2.SetAzimRxnAngle(decay1Phi);
m_step2.SetPolarRxnAngle(decay1Theta);
m_step2.SetAzimRxnAngle(decay1Phi);
step1.Calculate();
m_step1.Calculate();
step2.SetTarget(step1.GetResidual());
if(decay1costheta == -10) {
step2.ResetEjectile();
step2.ResetResidual();
if(decay1costheta == -10)
{
m_nuclei[4].vec4.SetPxPyPzE(0., 0., 0., m_nuclei[4].groundStateMass);
m_nuclei[5].vec4.SetPxPyPzE(0., 0., 0., m_nuclei[5].groundStateMass);
return;
}
step2.TurnOnResidualEloss();
step2.Calculate();
m_step2.SetResidualEnergyLoss(true);
m_step2.Calculate();
}

40
src/Mask/TwoStepSystem.h Normal file
View File

@ -0,0 +1,40 @@
#ifndef TWOSTEPSYSTEM_H
#define TWOSTEPSYSTEM_H
#include "ReactionSystem.h"
#include "AngularDistribution.h"
namespace Mask {
class TwoStepSystem : public ReactionSystem
{
public:
TwoStepSystem();
TwoStepSystem(const std::vector<int>& z, const std::vector<int>& a);
~TwoStepSystem();
bool SetNuclei(const std::vector<int>& z, const std::vector<int>& a) override;
void RunSystem() override;
std::vector<Nucleus>* GetNuclei() override;
virtual void SetDecay1Distribution(const std::string& filename) override { m_step2Distribution.ReadDistributionFile(filename); };
virtual void SetReactionThetaType(RxnThetaType type) override { m_step1.SetEjectileThetaType(type); };
int GetDecay1AngularMomentum() { return m_step2Distribution.GetL(); };
double GetDecay1BranchingRatio() { return m_step2Distribution.GetBranchingRatio(); };
private:
void LinkTarget() override;
void SetSystemEquation() override;
std::uniform_real_distribution<double> m_phi2Range;
Reaction m_step1, m_step2;
AngularDistribution m_step2Distribution;
};
}
#endif

View File

@ -1,48 +0,0 @@
/*
Class to represent a 3-space vector in both cartesian and spherical coordinates. Can perform vector
addition, subtraction, and dot product.
--GWM Dec 2020
*/
#include "Vec3.h"
namespace Mask {
Vec3::Vec3() {
m_data[0] = 0.;
m_data[1] = 0.;
m_data[2] = 0.;
}
Vec3::Vec3(double x, double y, double z) {
m_data[0] = x;
m_data[1] = y;
m_data[2] = z;
}
Vec3::~Vec3() {}
void Vec3::SetVectorCartesian(double x, double y, double z) {
m_data[0] = x;
m_data[1] = y;
m_data[2] = z;
}
void Vec3::SetVectorSpherical(double r, double theta, double phi) {
m_data[0] = r*std::cos(phi)*std::sin(theta);
m_data[1] = r*std::sin(phi)*std::sin(theta);
m_data[2] = r*std::cos(theta);
}
double Vec3::Dot(const Vec3& rhs) const {
return GetX()*rhs.GetX() + GetY()*rhs.GetY() + GetZ()*rhs.GetZ();
}
Vec3 Vec3::Cross(const Vec3& rhs) const {
double x = GetY()*rhs.GetZ() - GetZ()*rhs.GetY();
double y = GetZ()*rhs.GetX() - GetX()*rhs.GetZ();
double z = GetX()*rhs.GetY() - GetY()*rhs.GetX();
return Vec3(x,y,z);
}
}

View File

@ -1,73 +0,0 @@
/*
Class which represents a 4-momentum vector. Can perform vector addition, subtraction, dot product
and generate a boost vector to its rest frame as well as apply a boost to itself.
--GWM Dec 2020.
NOTE: uses (-,-,-,+) metric (same as ROOT convention)
*/
#include "Vec4.h"
namespace Mask {
Vec4::Vec4() {
for(auto& val: m_data)
val = 0.0;
for(auto& val: m_boost)
val = 0.0;
}
Vec4::Vec4(double px, double py, double pz, double E) {
m_data[0] = px;
m_data[1] = py;
m_data[2] = pz;
m_data[3] = E;
CalcBoostToCM();
}
Vec4::~Vec4() {}
void Vec4::SetVectorCartesian(double px, double py, double pz, double E) {
m_data[0] = px;
m_data[1] = py;
m_data[2] = pz;
m_data[3] = E;
CalcBoostToCM();
}
void Vec4::SetVectorSpherical(double theta, double phi, double p, double E) {
m_data[0] = p*cos(phi)*sin(theta);
m_data[1] = p*sin(phi)*sin(theta);
m_data[2] = p*cos(theta);
m_data[3] = E;
CalcBoostToCM();
}
void Vec4::CalcBoostToCM() {
m_boost[0] = m_data[0]/m_data[3];
m_boost[1] = m_data[1]/m_data[3];
m_boost[2] = m_data[2]/m_data[3];
}
void Vec4::ApplyBoost(const double* beta) {
double beta2 = beta[0]*beta[0] + beta[1]*beta[1] + beta[2]*beta[2];
double gamma = 1.0/std::sqrt(1.0 - beta2);
double bdotp = beta[0]*m_data[0] + beta[1]*m_data[1] + beta[2]*m_data[2];
double gfactor = beta2>0.0 ? (gamma - 1.0)/beta2 : 0.0;
SetVectorCartesian(GetPx()+gfactor*bdotp*beta[0]+gamma*beta[0]*GetE(),
GetPy()+gfactor*bdotp*beta[1]+gamma*beta[1]*GetE(),
GetPz()+gfactor*bdotp*beta[2]+gamma*beta[2]*GetE(),
gamma*(GetE() + bdotp));
}
double Vec4::Dot(const Vec4& rhs) const {
return GetE()*rhs.GetE() - GetPx()*rhs.GetPx() - GetPy()*rhs.GetPy() - GetPz()*rhs.GetPz();
}
Vec4 Vec4::Cross(const Vec4& rhs) const {
return Vec4();
}
}

View File

@ -1,5 +1,5 @@
add_executable(MaskApp)
target_include_directories(MaskApp PUBLIC ${MASK_INCLUDE_DIR})
target_include_directories(MaskApp PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/..)
target_sources(MaskApp PUBLIC
main.cpp

View File

@ -1,27 +1,32 @@
#include <iostream>
#include <string>
#include "Stopwatch.h"
#include "MaskFile.h"
#include "MaskApp.h"
#include "KinematicsExceptions.h"
#include "Mask/Stopwatch.h"
#include "Mask/MaskApp.h"
#include "Mask/KinematicsExceptions.h"
int main(int argc, char** argv) {
if(argc<2) {
int main(int argc, char** argv)
{
if(argc<2)
{
std::cerr<<"Incorrect number of arguments!"<<std::endl;
return 1;
}
Stopwatch sw;
Mask::Stopwatch sw;
Mask::MaskApp calculator;
sw.Start();
try {
if(!calculator.LoadConfig(argv[1])) {
try
{
if(!calculator.LoadConfig(argv[1]))
{
std::cerr<<"Unable to read input file!"<<std::endl;
return 1;
}
calculator.Run();
} catch(const std::exception& e) {
}
catch(const std::exception& e)
{
std::cerr<<"Exception caught! Information: "<<e.what()<<std::endl;
std::cerr<<"Terminating process."<<std::endl;
return 1;

View File

@ -1,15 +1,18 @@
find_package(ROOT REQUIRED)
add_executable(RootPlot)
target_include_directories(RootPlot
PUBLIC ${MASK_INCLUDE_DIR}
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/..
SYSTEM PUBLIC ${ROOT_INCLUDE_DIRS}
)
target_sources(RootPlot PUBLIC
RootPlotter.cpp
RootPlotter.h
main.cpp
)
target_link_libraries(RootPlot
MaskDict
Mask
${ROOT_LIBRARIES}
)

View File

@ -1,3 +0,0 @@
__pycache__
!.gitignore

View File

@ -1,80 +0,0 @@
#!/usr/bin/env python3
import numpy as np
import struct
class MaskFileData :
def __init__(self, n):
self.Z = np.zeros(n, dtype=int)
self.A = np.zeros(n, dtype=int)
self.dFlag = np.zeros(n, dtype=bool)
self.E = np.zeros(n)
self.KE = np.zeros(n)
self.p = np.zeros(n)
self.theta = np.zeros(n)
self.phi = np.zeros(n)
class MaskFile:
int_size = 4
double_size = 8
bool_size = 1
def __init__(self, filename=""):
self.eofFlag = False
self.openFlag = False
if filename != "" :
self.Open(filename)
def Open(self, filename):
self.filename = filename
self.file = open(self.filename, mode="rb")
if self.file.closed :
self.openFlag = False
else:
self.openFlag = True
def ReadHeader(self):
data = self.file.read(2*self.int_size)
(self.nsamples, self.rxntype) = struct.unpack("ii", data)
self.datasize = (5*self.double_size+2*self.int_size+self.bool_size)
self.datastr = "=ii?ddddd"
if self.rxntype == 0:
self.N_nuclei = 3
elif self.rxntype == 1:
self.N_nuclei = 4
elif self.rxntype == 2:
self.N_nuclei = 6
elif self.rxntype == 3:
self.N_nuclei = 8
def ReadData(self):
data = MaskFileData(self.N_nuclei)
for i in range(self.N_nuclei):
buffer = self.file.read(self.datasize)
(data.Z[i], data.A[i], data.dFlag[i], data.E[i], data.KE[i], data.p[i], data.theta[i], data.phi[i]) = struct.unpack(self.datastr, buffer)
if buffer == "":
self.eofFlag = True
return data
def Close(self):
self.file.close()
def main() :
file = MaskFile(filename="/data1/gwm17/mask_tests/7Bedp_870keV_beam_50CD2.mask")
file.ReadHeader()
print("samples: ", file.nsamples, "rxntype:", file.rxntype, "datasize:", file.datasize)
count=0
for i in range(file.nsamples):
file.ReadData()
count += 1
print("count:",count)
print("eofFlag:",file.eofFlag)
file.Close()
if __name__ == '__main__':
main()

View File

@ -1,70 +0,0 @@
#!/usr/bin/env python3
import numpy as np
import requests
import lxml.html as xhtml
class MassTable:
def __init__(self):
file = open("./etc/mass.txt","r")
self.mtable = {}
u2mev = 931.4940954
me = 0.000548579909 #amu
self.etable = {}
line = file.readline()
line = file.readline()
for line in file:
entries = line.split()
n = entries[0]
z = entries[1]
a = entries[2]
element = entries[3]
massBig = float(entries[4])
massSmall = float(entries[5])
key = '('+z+','+a+')'
value = ((massBig+massSmall*1e-6) - float(z)*me)*u2mev
self.mtable[key] = value
self.etable[key] = element
file.close()
def GetMass(self, z, a):
key = '('+str(z)+','+str(a)+')'
if key in self.mtable:
return self.mtable[key]
else:
return 0
def GetSymbol(self, z, a):
key = '('+str(z)+','+str(a)+')'
if key in self.etable:
return str(a)+self.etable[key]
else:
return 'none'
Masses = MassTable()
def GetExcitations(symbol):
levels = np.array(np.empty(0))
text = ''
site = requests.get("https://www.nndc.bnl.gov/nudat2/getdatasetClassic.jsp?nucleus="+symbol+"&unc=nds")
contents = xhtml.fromstring(site.content)
tables = contents.xpath("//table")
rows = tables[2].xpath("./tr")
for row in rows[1:-2]:
entries = row.xpath("./td")
if len(entries) != 0:
entry = entries[0]
data = entry.xpath("./a")
if len(data) == 0:
text = entry.text
else:
text = data[0].text
text = text.replace('?', '')
text = text.replace('\xa0\xa0','')
levels = np.append(levels, float(text)/1000.0)
return levels

View File

@ -1,106 +0,0 @@
#!/usr/bin/env python3
import numpy as np
from NucData import Masses
class Nucleus:
deg2rad = np.pi/180.0
def __init__(self, Z=0, A=0):
self.Z = Z
self.A = A
if Z != 0 and A != 0:
self.gsMass = Masses.GetMass(self.Z, self.A)
self.vec4 = np.zeros(4)
self.symbol = Masses.GetSymbol(self.Z, self.A)
self.vec4[3] = self.gsMass
def SetIsotope(self, Z, A):
self.gsMass = Masses.GetMass(Z, A)
self.symbol = Masses.GetSymbol(Z, A)
self.Z = Z
self.A = A
self.vec4 = np.zeros(4)
self.vec4[3] = self.gsMass
def SetVectorCart(self, px, py, pz, E):
self.vec4[0] = px
self.vec4[1] = py
self.vec4[2] = pz
self.vec4[3] = E
def SetVectorSpher(self, theta, phi, p, E):
self.vec4[0] = p*np.sin(theta)*np.cos(phi)
self.vec4[1] = p*np.sin(theta)*np.sin(phi)
self.vec4[2] = p*np.cos(theta)
self.vec4[3] = E
def __add__(self, other):
vec4 = self.vec4 + other.vec4
newNuc = Nucleus(self.Z + other.Z, self.A + other.A)
newNuc.SetVectorCart(vec4[0], vec4[1], vec4[2], vec4[3])
return newNuc
def __sub__(self, other):
vec4 = self.vec4 - other.vec4
newNuc = Nucleus(self.Z - other.Z, self.A - other.A)
newNuc.SetVectorCart(vec4[0], vec4[1], vec4[2], vec4[3])
return newNuc
def __str__(self):
return "Nucleus({0},{1}) with 4-vector({2})".format(self.Z, self.A, self.vec4)
def GetP(self):
return np.sqrt(self.vec4[0]**2.0 + self.vec4[1]**2.0 + self.vec4[2]**2.0)
def GetInvMass(self):
return np.sqrt(self.vec4[3]**2.0 - self.GetP()**2.0)
def GetKE(self):
return self.vec4[3] - self.GetInvMass()
def GetTheta(self):
return np.arccos(self.vec4[2]/self.GetP())
def GetPhi(self):
result = np.arctan2(self.vec4[1], self.vec4[0])
if result < 0.0:
result += 2.0*np.pi
return result
def GetExcitation(self):
return self.GetInvMass() - self.gsMass
def GetBoostToCMFrame(self):
boost_vec = np.zeros(3)
boost_vec[0] = self.vec4[0]/self.vec4[3]
boost_vec[1] = self.vec4[1]/self.vec4[3]
boost_vec[2] = self.vec4[2]/self.vec4[3]
return boost_vec
def ApplyBoost(self, boost_vec):
beta2 = np.linalg.norm(boost_vec)**2.0
gamma = 1.0/np.sqrt(1.0 - beta2)
bdotp = boost_vec[0]*self.vec4[0] + boost_vec[1]*self.vec4[1] + boost_vec[2]*self.vec4[2]
gfactor = (gamma-1.0)/beta2 if beta2 > 0.0 else 0.0
px = self.vec4[0]+gfactor*bdotp*boost_vec[0]+gamma*boost_vec[0]*self.vec4[3]
py = self.vec4[1]+gfactor*bdotp*boost_vec[1]+gamma*boost_vec[1]*self.vec4[3]
pz = self.vec4[2]+gfactor*bdotp*boost_vec[2]+gamma*boost_vec[2]*self.vec4[3]
E = gamma*(self.vec4[3] + bdotp)
self.SetVectorCart(px, py, pz, E);
def main():
nuc = Nucleus(1,1)
print("First",nuc)
nuc2 = Nucleus(2,4)
print("Second", nuc2)
result = nuc + nuc2
print("Addition", result)
result2 = nuc2 - nuc
print("Subtraction", result2)
if __name__ == '__main__':
main()

View File

@ -1,135 +0,0 @@
#!/usr/bin/env python3
import numpy as np
import matplotlib.pyplot as plt
from Nucleus import Nucleus
from MaskFile import MaskFile, MaskFileData
from NucData import Masses
import pickle
import sys
def PlotData(inputname, outputname):
rad2deg = 180.0/np.pi
datafile = MaskFile(inputname)
datafile.ReadHeader()
print("MaskFile opened -- rxntype:", datafile.rxntype, "number of samples:", datafile.nsamples)
data = MaskFileData(datafile.N_nuclei)
ke = np.zeros((datafile.N_nuclei, datafile.nsamples))
ke_d = np.zeros((datafile.N_nuclei, datafile.nsamples))
theta = np.zeros((datafile.N_nuclei, datafile.nsamples))
theta_d = np.zeros((datafile.N_nuclei, datafile.nsamples))
phi = np.zeros((datafile.N_nuclei, datafile.nsamples))
phi_d = np.zeros((datafile.N_nuclei, datafile.nsamples))
detect_mask = np.ones((datafile.N_nuclei, datafile.nsamples), dtype=bool)
names = []
for i in range(datafile.N_nuclei):
names.append(" ")
nuc = Nucleus()
for i in range(datafile.nsamples):
data = datafile.ReadData()
if i == 0:
for j in range(datafile.N_nuclei):
names[j] = Masses.GetSymbol(data.Z[j], data.A[j])
for j in range(datafile.N_nuclei):
nuc.SetIsotope(data.Z[j], data.A[j])
nuc.SetVectorSpher(data.theta[j], data.phi[j], data.p[j], data.E[j])
ke[j][i] = nuc.GetKE()
theta[j][i] = data.theta[j]*rad2deg
phi[j][i] = data.phi[j]*rad2deg
if data.dFlag[j] == True:
ke_d[j][i] = data.KE[j]
theta_d[j][i] = data.theta[j]*rad2deg
phi_d[j][i] = data.phi[j]*rad2deg
else:
detect_mask[j][i] = False
datafile.Close()
#Remove empty values from detection arrays
final_theta_d = theta_d[detect_mask]
final_phi_d = phi_d[detect_mask]
final_ke_d = ke_d[detect_mask]
#figs = {}
#axes = {}
'''
for i in range(len(names)):
figs[i], axes[i] = plt.subplots(2,2)
'''
fig, axes = plt.subplots(len(names)-1,4)
fig.set_size_inches(12, 12)
for i in range(1, len(names)):
'''
axes[i][0][0].plot(theta[i], ke[i], marker=',', linestyle='None')
axes[i][0][0].set_title(names[i]+" KE vs. Theta")
axes[i][0][0].set_xlabel(r"$\theta$ (degrees)")
axes[i][0][0].set_ylabel("KE (MeV)")
axes[i][0][1].plot(phi[i], ke[i], marker=",", linestyle='None')
axes[i][0][1].set_title(names[i]+" KE vs. Phi")
axes[i][0][1].set_xlabel(r"$\phi$ (degrees)")
axes[i][0][1].set_ylabel("KE (MeV)")
axes[i][1][0].plot(theta_d[i], ke_d[i], marker=',', linestyle='None')
axes[i][1][0].set_title(names[i]+" KE vs. Theta -- Detected")
axes[i][1][0].set_xlabel(r"$\theta$ (degrees)")
axes[i][1][0].set_ylabel("KE (MeV)")
axes[i][1][1].plot(phi_d[i], ke_d[i], marker=",", linestyle='None')
axes[i][1][1].set_title(names[i]+" KE vs. Phi -- Detected")
axes[i][1][1].set_xlabel(r"$\phi$ (degrees)")
axes[i][1][1].set_ylabel("KE (MeV)")
'''
axes[i-1][0].plot(theta[i], ke[i], marker=',', linestyle='None')
axes[i-1][0].set_title(names[i]+" KE vs. Theta")
axes[i-1][0].set_xlabel(r"$\theta$ (degrees)")
axes[i-1][0].set_ylabel("KE (MeV)")
axes[i-1][1].plot(phi[i], ke[i], marker=",", linestyle='None')
axes[i-1][1].set_title(names[i]+" KE vs. Phi")
axes[i-1][1].set_xlabel(r"$\phi$ (degrees)")
axes[i-1][1].set_ylabel("KE (MeV)")
axes[i-1][2].plot(theta_d[i], ke_d[i], marker=',', linestyle='None')
axes[i-1][2].set_title(names[i]+" KE vs. Theta -- Detected")
axes[i-1][2].set_xlabel(r"$\theta$ (degrees)")
axes[i-1][2].set_ylabel("KE (MeV)")
axes[i-1][3].plot(phi_d[i], ke_d[i], marker=",", linestyle='None')
axes[i-1][3].set_title(names[i]+" KE vs. Phi -- Detected")
axes[i-1][3].set_xlabel(r"$\phi$ (degrees)")
axes[i-1][3].set_ylabel("KE (MeV)")
plt.tight_layout()
plt.show(block=True)
print("Writing figure to file:", outputname)
with open(outputname, "wb") as outfile:
pickle.dump(fig, outfile)
outfile.close()
print("Finished.")
def main():
if len(sys.argv) == 3:
PlotData(sys.argv[1], sys.argv[2])
else:
print("Unable to run PyPlotter, incorrect number of arguments! Need an input datafile name, and an output plot file name")
if __name__ == '__main__':
main()

View File

@ -1,32 +0,0 @@
#!/usr/bin/env python3
import matplotlib.pyplot as plt
import numpy as np
import pickle
import sys
def SetManager(figure):
dummy = plt.figure()
manager = dummy.canvas.manager
manager.canvas.figure = figure
figure.set_canvas(manager.canvas)
def ViewPyPlots(filename):
figure = pickle.load(open(filename, "rb"))
SetManager(figure)
figure.set_size_inches(12, 12)
plt.tight_layout()
plt.show(block=True)
def main():
if len(sys.argv) == 2:
ViewPyPlots(sys.argv[1])
else:
print("Unable to run ViewPyPlots, incorrect number of commandline arguments -- requires an input pickle file")
if __name__ == '__main__':
main()

View File

@ -1,323 +0,0 @@
#include "RootPlotter.h"
#include <TFile.h>
#include <TVector3.h>
#include <iostream>
RootPlotter::RootPlotter() :
table(new THashTable())
{
}
RootPlotter::~RootPlotter() {}
void RootPlotter::FillData(const Mask::Nucleus& nuc, double detKE, const std::string& modifier) {
std::string sym = nuc.GetIsotopicSymbol();
std::string ke_vs_th_name = sym + modifier + "_ke_vs_theta";
std::string ke_vs_th_title = ke_vs_th_name + ";#theta_{lab} (degrees);Kinetic Energy (MeV)";
std::string ke_vs_ph_name = sym + modifier + "_ke_vs_phi";
std::string ke_vs_ph_title = ke_vs_ph_name + ";#phi_{lab} (degrees);Kinetic Energy (MeV)";
std::string th_vs_ph_name = sym + modifier + "_theta_vs_phi";
std::string th_vs_ph_title = th_vs_ph_name + ";#theta_{lab};#phi_{lab}";
std::string ex_name = sym + modifier + "_ex";
std::string ex_title = ex_name + ";E_{ex} (MeV);counts";
std::string angdist_name = sym + modifier +"_angDist";
std::string angdist_title = angdist_name+";cos#right(#theta_{CM}#left);counts";
if(detKE == 0.0)
{
MyFill(ke_vs_th_name.c_str(), ke_vs_th_title.c_str(), nuc.GetTheta()*rad2deg, nuc.GetKE(), 2);
MyFill(ke_vs_ph_name.c_str(), ke_vs_ph_title.c_str(), nuc.GetPhi()*rad2deg, nuc.GetKE(), 4);
MyFill(th_vs_ph_name.c_str(), th_vs_ph_title.c_str(), nuc.GetTheta()*rad2deg, nuc.GetPhi()*rad2deg, 2);
MyFill(ex_name.c_str(),ex_title.c_str(),260,-1.0,25,nuc.GetExcitationEnergy());
MyFill(angdist_name.c_str(), angdist_title.c_str(),20,-1.0,1.0,std::cos(nuc.GetThetaCM()));
}
else
{
MyFill(ke_vs_th_name.c_str(), ke_vs_th_title.c_str(), nuc.GetTheta()*rad2deg, detKE, 2);
MyFill(ke_vs_ph_name.c_str(), ke_vs_ph_title.c_str(), nuc.GetPhi()*rad2deg, detKE, 4);
MyFill(th_vs_ph_name.c_str(), th_vs_ph_title.c_str(), nuc.GetTheta()*rad2deg, nuc.GetPhi()*rad2deg, 2);
MyFill(ex_name.c_str(),ex_title.c_str(),260,-1.0,25,nuc.GetExcitationEnergy());
MyFill(angdist_name.c_str(), angdist_title.c_str(),20,-1.0,1.0,std::cos(nuc.GetThetaCM()));
}
}
void RootPlotter::FillCorrelations(const Mask::MaskFileData& data, Mask::RxnType type)
{
std::string theta_eject_theta_resid_name = "theta_eject_theta_resid_cor";
std::string theta_eject_theta_resid_title = theta_eject_theta_resid_name + ";#theta_{lab} Ejectile (deg);#theta_{lab} Residual";
if(type == Mask::RxnType::PureDecay)
{
MyFill(theta_eject_theta_resid_name, theta_eject_theta_resid_title, data.theta[1]*rad2deg, data.theta[2]*rad2deg, 4);
}
else
{
MyFill(theta_eject_theta_resid_name, theta_eject_theta_resid_title, data.theta[2]*rad2deg, data.theta[3]*rad2deg, 4);
}
if(type == Mask::RxnType::TwoStepRxn || type == Mask::RxnType::ThreeStepRxn)
{
TVector3 p1, p2;
p1.SetMagThetaPhi(1.0, data.theta[3], data.phi[3]);
p2.SetMagThetaPhi(1.0, data.theta[4], data.phi[4]);
double theta_resid_break1 = std::acos(p1.Dot(p2));
std::string theta_break1_theta_break2_name = "theta_break1_theta_break2_cor";
std::string theta_break1_theta_break2_title = theta_break1_theta_break2_name + ";#theta_{lab} Breakup1 (deg);#theta_{lab} Breakup2 (deg)";
MyFill(theta_break1_theta_break2_name, theta_break1_theta_break2_title, data.theta[4]*rad2deg, data.theta[5]*rad2deg, 4);
std::string theta_resid_theta_break1_name = "theta_resid_theta_break1_cor";
std::string theta_resid_theta_break1_title = theta_resid_theta_break1_name + ";#theta_{lab} Residual (deg);#theta_{lab} Breakup1 (deg)";
MyFill(theta_resid_theta_break1_name, theta_resid_theta_break1_title, data.theta[3]*rad2deg, data.theta[4]*rad2deg, 4);
std::string ke_break1_theta_rel_name = "ke_break1_theta_rel";
std::string ke_break1_theta_rel_title = ke_break1_theta_rel_name + ";#theta_{resid-break1};KE_{break1} (MeV)";
MyFill(ke_break1_theta_rel_name, ke_break1_theta_rel_title, theta_resid_break1*rad2deg, data.KE[4], 4);
}
if(type == Mask::RxnType::ThreeStepRxn)
{
std::string theta_break3_theta_break4_name = "theta_break3_theta_break4_cor";
std::string theta_break3_theta_break4_title = theta_break3_theta_break4_name + ";#theta_{lab} Breakup3 (deg);#theta_{lab} Breakup4 (deg)";
MyFill(theta_break3_theta_break4_name, theta_break3_theta_break4_title, data.theta[6]*rad2deg, data.theta[7]*rad2deg, 4);
}
}
void RootPlotter::FillCorrelationsDetected(const Mask::MaskFileData& data, Mask::RxnType type)
{
std::string theta_eject_theta_resid_name = "theta_eject_theta_resid_cor_detected";
std::string theta_eject_theta_resid_title = theta_eject_theta_resid_name + ";#theta_{lab} Ejectile (deg);#theta_{lab} Residual";
if(type == Mask::RxnType::PureDecay && data.detect_flag[1] && data.detect_flag[2])
{
MyFill(theta_eject_theta_resid_name, theta_eject_theta_resid_title, data.theta[1]*rad2deg, data.theta[2]*rad2deg, 4);
}
else if(data.detect_flag[2] && data.detect_flag[3])
{
MyFill(theta_eject_theta_resid_name, theta_eject_theta_resid_title, data.theta[2]*rad2deg, data.theta[3]*rad2deg, 4);
}
if((type == Mask::RxnType::TwoStepRxn || type == Mask::RxnType::ThreeStepRxn) && data.detect_flag[4])
{
TVector3 p1, p2;
p1.SetMagThetaPhi(1.0, data.theta[3], data.phi[3]);
p2.SetMagThetaPhi(1.0, data.theta[4], data.phi[4]);
double theta_resid_break1 = std::acos(p1.Dot(p2));
std::string theta_resid_theta_break1_name = "theta_resid_theta_break1_cor_detected";
std::string theta_resid_theta_break1_title = theta_resid_theta_break1_name + ";#theta_{lab} Residual (deg);#theta_{lab} Breakup1 (deg)";
MyFill(theta_resid_theta_break1_name, theta_resid_theta_break1_title, data.theta[3]*rad2deg, data.theta[4]*rad2deg, 4);
std::string ke_break1_theta_rel_name = "ke_break1_theta_rel_detected";
std::string ke_break1_theta_rel_title = ke_break1_theta_rel_name + ";#theta_{resid-break1};KE_{break1} (MeV)";
MyFill(ke_break1_theta_rel_name, ke_break1_theta_rel_title, theta_resid_break1*rad2deg, data.KE[4], 4);
}
if((type == Mask::RxnType::TwoStepRxn || type == Mask::RxnType::ThreeStepRxn) && data.detect_flag[4] && data.detect_flag[5])
{
std::string theta_break1_theta_break2_name = "theta_break1_theta_break2_cor_detected";
std::string theta_break1_theta_break2_title = theta_break1_theta_break2_name + ";#theta_{lab} Breakup1 (deg);#theta_{lab} Breakup2 (deg)";
MyFill(theta_break1_theta_break2_name, theta_break1_theta_break2_title, data.theta[4]*rad2deg, data.theta[5]*rad2deg, 4);
}
if(type == Mask::RxnType::ThreeStepRxn && data.detect_flag[6] && data.detect_flag[7])
{
std::string theta_break3_theta_break4_name = "theta_break3_theta_break4_cor_detected";
std::string theta_break3_theta_break4_title = theta_break3_theta_break4_name + ";#theta_{lab} Breakup3 (deg);#theta_{lab} Breakup4 (deg)";
MyFill(theta_break3_theta_break4_name, theta_break3_theta_break4_title, data.theta[6]*rad2deg, data.theta[7]*rad2deg, 4);
}
}
void RootPlotter::MyFill(const std::string& name, const std::string& title, int bins, float min, float max, double val) {
TH1F* h = (TH1F*) table->FindObject(name.c_str());
if(h) {
h->Fill(val);
} else {
h = new TH1F(name.c_str(), title.c_str(), bins, min, max);
h->Fill(val);
table->Add(h);
}
}
void RootPlotter::MyFill(const std::string& name, const std::string& title, int binsx, float minx, float maxx, int binsy, float miny, float maxy, double valx, double valy) {
TH2F* h = (TH2F*) table->FindObject(name.c_str());
if(h) {
h->Fill(valx, valy);
} else {
h = new TH2F(name.c_str(), title.c_str(), binsx, minx, maxx, binsy, miny, maxy);
h->Fill(valx, valy);
table->Add(h);
}
}
void RootPlotter::MyFill(const std::string& name, const std::string& title, double valx, double valy, int color) {
for(auto& g : graphs) {
if(g.name == name) {
g.xvec.push_back(valx);
g.yvec.push_back(valy);
return;
}
}
GraphData new_g;
new_g.name = name;
new_g.title = title;
new_g.xvec.push_back(valx);
new_g.yvec.push_back(valy);
new_g.color = color;
graphs.push_back(new_g);
}
void RootPlotter::GenerateGraphs() {
for(auto& g : graphs) {
TGraph* graph = new TGraph(g.xvec.size(), &(g.xvec[0]), &(g.yvec[0]));
graph->SetName(g.name.c_str());
graph->SetTitle(g.title.c_str());
graph->SetMarkerColor(g.color);
table->Add(graph);
garbage_collection.push_back(graph);
}
}
std::vector<Mask::Nucleus> GetParents(const Mask::MaskFileData& data, Mask::RxnType rxn_type)
{
std::vector<Mask::Nucleus> parents;
Mask::Nucleus temp1, temp2, temp3;
switch(rxn_type)
{
case Mask::RxnType::None : break;
case Mask::RxnType::PureDecay :
{
temp1.SetIsotope(data.Z[0], data.A[0]);
temp1.SetVectorSpherical(data.theta[0], data.phi[0], data.p[0], data.E[0]);
parents.push_back(temp1);
return parents;
}
case Mask::RxnType::OneStepRxn :
{
temp1.SetIsotope(data.Z[0], data.A[0]);
temp1.SetVectorSpherical(data.theta[0], data.phi[0], data.p[0], data.E[0]);
temp2.SetIsotope(data.Z[1], data.A[1]);
temp2.SetVectorSpherical(data.theta[1], data.phi[1], data.p[1], data.E[1]);
temp3 = temp1 + temp2;
parents.push_back(temp3);
return parents;
}
case Mask::RxnType::TwoStepRxn :
{
temp1.SetIsotope(data.Z[0], data.A[0]);
temp1.SetVectorSpherical(data.theta[0], data.phi[0], data.p[0], data.E[0]);
temp2.SetIsotope(data.Z[1], data.A[1]);
temp2.SetVectorSpherical(data.theta[1], data.phi[1], data.p[1], data.E[1]);
temp3 = temp1 + temp2;
parents.push_back(temp3);
temp3.SetIsotope(data.Z[3], data.A[3]);
temp3.SetVectorSpherical(data.theta[3], data.phi[3], data.p[3], data.E[3]);
parents.push_back(temp3);
return parents;
}
case Mask::RxnType::ThreeStepRxn :
{
temp1.SetIsotope(data.Z[0], data.A[0]);
temp1.SetVectorSpherical(data.theta[0], data.phi[0], data.p[0], data.E[0]);
temp2.SetIsotope(data.Z[1], data.A[1]);
temp2.SetVectorSpherical(data.theta[1], data.phi[1], data.p[1], data.E[1]);
temp3 = temp1 + temp2;
parents.push_back(temp3);
temp3.SetIsotope(data.Z[3], data.A[3]);
temp3.SetVectorSpherical(data.theta[3], data.phi[3], data.p[3], data.E[3]);
parents.push_back(temp3);
temp3.SetIsotope(data.Z[5], data.A[5]);
temp3.SetVectorSpherical(data.theta[5], data.phi[5], data.p[5], data.E[5]);
parents.push_back(temp3);
return parents;
}
}
return parents;
}
void SetThetaCM(Mask::Nucleus& daughter, const Mask::Nucleus& parent)
{
const double* boost = parent.GetBoost();
double boost2cm[3];
double boost2lab[3];
for(int i=0; i<3; i++)
{
boost2lab[i] = boost[i];
boost2cm[i] = -1.0*boost[i];
}
daughter.ApplyBoost(boost2cm);
daughter.SetThetaCM(daughter.GetTheta());
daughter.ApplyBoost(boost2lab);
}
int main(int argc, char** argv) {
if(argc != 3) {
std::cout<<"Unable to run ROOT plotting tool with incorrect number of arguments! Expected 2 args, given: "<<argc<<" Exiting."<<std::endl;
return 1;
}
std::string inputname = argv[1];
std::string outputname = argv[2];
Mask::MaskFile input(inputname, Mask::MaskFile::FileType::read);
TFile* root_out = TFile::Open(outputname.c_str(), "RECREATE");
RootPlotter plotter;
Mask::MaskFileHeader header = input.ReadHeader();
std::cout<<"File Header -- rxn type: "<<GetStringFromRxnType(header.rxn_type)<<" nsamples: "<<header.nsamples<<std::endl;
Mask::MaskFileData data;
Mask::Nucleus nucleus;
std::vector<Mask::Nucleus> parents; //for use with CM theta calc
double flush_frac = 0.05;
int count = 0, flush_val = flush_frac*header.nsamples, flush_count = 0;
while(true) {
if(count == flush_val) {
count = 0;
flush_count++;
std::cout<<"\rPercent of file processed: "<<flush_frac*flush_count*100<<"%"<<std::flush;
}
data = input.ReadData();
if(data.eof)
break;
parents = GetParents(data, header.rxn_type);
for(unsigned int i=0; i<data.Z.size(); i++) {
nucleus.SetIsotope(data.Z[i], data.A[i]);
nucleus.SetVectorSpherical(data.theta[i], data.phi[i], data.p[i], data.E[i]);
/*
Little dirty, but works well. Save theta CM using parent from specific rxn step.
I.e. ejectile calculated from first parent, break1 from second parent, break3 from third...
*/
if(i==1 || i==2 || i==3)
{
SetThetaCM(nucleus, parents[0]);
}
else if (i==4 || i==5)
{
SetThetaCM(nucleus, parents[1]);
}
else if(i==6 || i==7)
{
SetThetaCM(nucleus, parents[2]);
}
plotter.FillData(nucleus);
if(data.detect_flag[i] == true) {
plotter.FillData(nucleus, data.KE[i], "detected");
}
}
plotter.FillCorrelations(data, header.rxn_type);
plotter.FillCorrelationsDetected(data, header.rxn_type);
count++;
}
std::cout<<std::endl;
input.Close();
root_out->cd();
plotter.GetTable()->Write();
root_out->Close();
return 0;
}

View File

@ -0,0 +1,148 @@
#include "RootPlotter.h"
#include <TFile.h>
#include <TTree.h>
#include <TVector3.h>
#include <iostream>
static double FullPhi(double phi)
{
return phi < 0.0 ? 2.0*M_PI + phi : phi;
}
RootPlotter::RootPlotter()
{
TH1::AddDirectory(kFALSE);
//Enforce dictionary linking
if(Mask::EnforceDictionaryLinked())
{
std::cout<<"Dictionary Linked"<<std::endl;
}
}
RootPlotter::~RootPlotter() {}
void RootPlotter::Run(const std::string& inputname, const std::string& outputname)
{
TFile* input = TFile::Open(inputname.c_str(), "READ");
TTree* tree = (TTree*) input->Get("SimTree");
std::vector<Mask::Nucleus>* dataHandle = new std::vector<Mask::Nucleus>();
tree->SetBranchAddress("nuclei", &dataHandle);
TFile* output = TFile::Open(outputname.c_str(), "RECREATE");
double flushFrac = 0.05;
uint64_t nentries = tree->GetEntries();
uint64_t flushVal = flushFrac*nentries;
uint64_t count=0;
uint64_t flushCount = 0;
for(uint64_t i=0; i<nentries; i++)
{
count++;
if(count == flushVal)
{
count = 0;
flushCount++;
std::cout<<"\rPercent of data processed: "<<flushCount*flushFrac*100<<"%"<<std::flush;
}
tree->GetEntry(i);
for(Mask::Nucleus& nuc : *(dataHandle))
{
FillData(nuc);
}
}
std::cout<<std::endl;
input->Close();
delete dataHandle;
output->cd();
for(auto& obj : m_map)
obj.second->Write();
output->Close();
}
void RootPlotter::FillData(const Mask::Nucleus& nuc)
{
std::string modifier = "";
if(nuc.isDetected)
modifier = "detected";
std::string sym = nuc.isotopicSymbol;
std::string ke_vs_th_name = sym + modifier + "_ke_vs_theta";
std::string ke_vs_th_title = ke_vs_th_name + ";#theta_{lab} (degrees);Kinetic Energy (MeV)";
std::string ke_vs_ph_name = sym + modifier + "_ke_vs_phi";
std::string ke_vs_ph_title = ke_vs_ph_name + ";#phi_{lab} (degrees);Kinetic Energy (MeV)";
std::string th_vs_ph_name = sym + modifier + "_theta_vs_phi";
std::string th_vs_ph_title = th_vs_ph_name + ";#theta_{lab};#phi_{lab}";
std::string ex_name = sym + modifier + "_ex";
std::string ex_title = ex_name + ";E_{ex} (MeV);counts";
std::string angdist_name = sym + modifier +"_angDist";
std::string angdist_title = angdist_name+";cos#right(#theta_{CM}#left);counts";
MyFill(ke_vs_th_name.c_str(), ke_vs_th_title.c_str(), nuc.vec4.Theta()*s_rad2deg, nuc.GetKE(), 2);
MyFill(ke_vs_ph_name.c_str(), ke_vs_ph_title.c_str(), FullPhi(nuc.vec4.Phi())*s_rad2deg, nuc.GetKE(), 4);
MyFill(th_vs_ph_name.c_str(), th_vs_ph_title.c_str(), nuc.vec4.Theta()*s_rad2deg, FullPhi(nuc.vec4.Phi())*s_rad2deg, 2);
MyFill(ex_name.c_str(),ex_title.c_str(),260,-1.0,25,nuc.GetExcitationEnergy());
MyFill(angdist_name.c_str(), angdist_title.c_str(),20,-1.0,1.0,std::cos(nuc.thetaCM));
if(nuc.isDetected)
{
MyFill(ke_vs_th_name.c_str(), ke_vs_th_title.c_str(), nuc.vec4.Theta()*s_rad2deg, nuc.detectedKE, 2);
MyFill(ke_vs_ph_name.c_str(), ke_vs_ph_title.c_str(), FullPhi(nuc.vec4.Phi())*s_rad2deg, nuc.detectedKE, 4);
MyFill(th_vs_ph_name.c_str(), th_vs_ph_title.c_str(), nuc.vec4.Theta()*s_rad2deg, FullPhi(nuc.vec4.Phi())*s_rad2deg, 2);
MyFill(ex_name.c_str(),ex_title.c_str(),260,-1.0,25,nuc.GetExcitationEnergy());
MyFill(angdist_name.c_str(), angdist_title.c_str(),20,-1.0,1.0,std::cos(nuc.thetaCM));
}
}
void RootPlotter::MyFill(const std::string& name, const std::string& title, int bins, float min, float max, double val)
{
auto iter = m_map.find(name);
if(iter != m_map.end())
{
std::shared_ptr<TH1> h = std::static_pointer_cast<TH1>(iter->second);
h->Fill(val);
}
else
{
std::shared_ptr<TH1F> h = std::make_shared<TH1F>(name.c_str(), title.c_str(), bins, min, max);
h->Fill(val);
m_map[name] = h;
}
}
void RootPlotter::MyFill(const std::string& name, const std::string& title, int binsx, float minx, float maxx,
int binsy, float miny, float maxy, double valx, double valy)
{
auto iter = m_map.find(name);
if(iter != m_map.end())
{
std::shared_ptr<TH2> h = std::static_pointer_cast<TH2>(iter->second);
h->Fill(valx, valy);
}
else
{
std::shared_ptr<TH2F> h = std::make_shared<TH2F>(name.c_str(), title.c_str(), binsx, minx, maxx, binsy, miny, maxy);
h->Fill(valx, valy);
m_map[name] = h;
}
}
void RootPlotter::MyFill(const std::string& name, const std::string& title, double valx, double valy, int color)
{
auto iter = m_map.find(name);
if(iter != m_map.end())
{
std::shared_ptr<TGraph> g = std::static_pointer_cast<TGraph>(iter->second);
g->SetPoint(g->GetN(), valx, valy);
}
else
{
std::shared_ptr<TGraph> g = std::make_shared<TGraph>(1, &valx, &valy);
g->SetName(name.c_str());
g->SetTitle(title.c_str());
g->SetMarkerColor(color);
m_map[name] = g;
}
}

View File

@ -0,0 +1,34 @@
#ifndef ROOTPLOTTER_H
#define ROOTPLOTTER_H
#include <vector>
#include <string>
#include <unordered_map>
#include "Nucleus.h"
#include <TH1.h>
#include <TH2.h>
#include <TGraph.h>
class RootPlotter
{
public:
RootPlotter();
~RootPlotter();
void Run(const std::string& inputname, const std::string& outputname);
private:
void FillData(const Mask::Nucleus& nuc);
void MyFill(const std::string& name, const std::string& title, int bins, float min, float max, double val);
void MyFill(const std::string& name, const std::string& title, int binsx, float minx, float maxx, int binsy, float miny, float maxy,
double valx, double valy);
void MyFill(const std::string& name, const std::string& title, double valx, double valy, int color); //TGraph
std::unordered_map<std::string, std::shared_ptr<TObject>> m_map;
static constexpr double s_rad2deg = 180.0/M_PI;
};
#endif

14
src/Plotters/main.cpp Normal file
View File

@ -0,0 +1,14 @@
#include "RootPlotter.h"
#include <iostream>
int main(int argc, char** argv)
{
if(argc != 3)
{
std::cerr<<"Root plotter requires two commandline arguments: path to input file and path to outputfile"<<std::endl;
return 1;
}
RootPlotter plotter;
plotter.Run(argv[1], argv[2]);
}