mirror of
https://github.com/gwm17/Mask.git
synced 2024-11-22 10:18:50 -05:00
commit
d857ad9d4d
5
.gitignore
vendored
5
.gitignore
vendored
|
@ -9,14 +9,15 @@
|
|||
*.pcm
|
||||
*.o
|
||||
*.a
|
||||
*.so
|
||||
*.swp
|
||||
*.pickle
|
||||
.DS_Store
|
||||
Makefile
|
||||
*.make
|
||||
__pycache__
|
||||
.vscode/
|
||||
build/
|
||||
lib/
|
||||
bin/
|
||||
|
||||
|
||||
###Keep this 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)
|
60
README.md
60
README.md
|
@ -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
5
bin/.gitignore
vendored
|
@ -1,5 +0,0 @@
|
|||
###keep only the directory, not the contents###
|
||||
*
|
||||
!.gitignore
|
||||
!PyPlotter
|
||||
!PyPlotViewer
|
|
@ -1,5 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
FileName=$1;
|
||||
|
||||
./src/Plotters/Python/ViewPyPlots.py ${FileName}
|
|
@ -1,6 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
InputFile=$1;
|
||||
OutputFile=$2;
|
||||
|
||||
./src/Plotters/Python/PyPlotter.py ${InputFile} ${OutputFile}
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
29
input.txt
29
input.txt
|
@ -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
|
||||
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
3
objs/.gitignore
vendored
|
@ -1,3 +0,0 @@
|
|||
###keep only the directory, not the contents###
|
||||
*
|
||||
!.gitignore
|
130
premake5.lua
130
premake5.lua
|
@ -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"
|
|
@ -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();
|
|
@ -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();
|
||||
|
|
64
src/Detectors/AnasenEfficiency.h
Normal file
64
src/Detectors/AnasenEfficiency.h
Normal 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
|
|
@ -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
|
||||
)
|
||||
|
|
|
@ -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
|
|
@ -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);
|
||||
}
|
65
src/Detectors/QQQDetector.h
Normal file
65
src/Detectors/QQQDetector.h
Normal 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
|
|
@ -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);
|
||||
}
|
||||
|
|
189
src/Detectors/SabreDetector.h
Normal file
189
src/Detectors/SabreDetector.h
Normal 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
|
|
@ -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)
|
||||
{
|
||||
|
||||
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
|
||||
//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);
|
||||
m_degradedDetectors[0] = true;
|
||||
m_degradedDetectors[1] = true;
|
||||
m_degradedDetectors[2] = false;
|
||||
m_degradedDetectors[3] = false;
|
||||
m_degradedDetectors[4] = true;
|
||||
|
||||
|
||||
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);
|
||||
//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]++;
|
||||
}
|
||||
|
|
51
src/Detectors/SabreEfficiency.h
Normal file
51
src/Detectors/SabreEfficiency.h
Normal 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
|
|
@ -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;
|
||||
|
|
82
src/Detectors/StripDetector.h
Normal file
82
src/Detectors/StripDetector.h
Normal 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
|
|
@ -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);
|
||||
//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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
35
src/Mask/AngularDistribution.h
Normal file
35
src/Mask/AngularDistribution.h
Normal 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
|
|
@ -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})
|
|
@ -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()
|
||||
{
|
||||
std::stringstream stream;
|
||||
stream << m_nuclei[0].isotopicSymbol << "->"
|
||||
<< m_nuclei[1].isotopicSymbol << "+"
|
||||
<< m_nuclei[2].isotopicSymbol;
|
||||
m_sysEquation = stream.str();
|
||||
}
|
||||
|
||||
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::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
36
src/Mask/DecaySystem.h
Normal 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
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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()));
|
||||
eloss += m_layers[rxnLayer].GetEnergyLossFractionalDepth(ze, ae, newEnergy, angle, m_fractionalDepthDistribution(gen.GetGenerator()));
|
||||
newEnergy = startEnergy - eloss;
|
||||
} else {
|
||||
eloss += layers[i].GetEnergyLossTotal(ze, ae, newEnergy, angle);
|
||||
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()));
|
||||
eloss += m_layers[rxnLayer].GetEnergyLossFractionalDepth(ze, ae, newEnergy, angle, m_fractionalDepthDistribution(gen.GetGenerator()));
|
||||
newEnergy = startEnergy - eloss;
|
||||
} else {
|
||||
eloss += layers[i].GetEnergyLossTotal(ze, ae, newEnergy, angle);
|
||||
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);
|
||||
for(std::size_t i=(m_layers.size()-1); 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;
|
||||
}
|
||||
} else {
|
||||
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);
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
|
@ -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]);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
7
src/Mask/LinkDef_Nucleus.h
Normal file
7
src/Mask/LinkDef_Nucleus.h
Normal 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
|
|
@ -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,66 +30,34 @@ 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);
|
||||
z = std::stoi(junk);
|
||||
input>>a;
|
||||
zvec.push_back(z);
|
||||
avec.push_back(a);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RxnType::TwoStepRxn:
|
||||
|
||||
m_system = CreateSystem(zvec, avec);
|
||||
if(m_system == nullptr)
|
||||
{
|
||||
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:
|
||||
std::cerr<<"Failure to parse reaction system... configuration not loaded."<<std::endl;
|
||||
return false;
|
||||
}
|
||||
m_sys->SetNuclei(zvec, avec);
|
||||
|
||||
int nlayers;
|
||||
double thickness;
|
||||
|
@ -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
37
src/Mask/MaskApp.h
Normal 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
|
|
@ -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;
|
||||
}
|
||||
|
||||
};
|
|
@ -10,38 +10,41 @@ Written by G.W. McCann Aug. 2020
|
|||
*/
|
||||
#include "MassLookup.h"
|
||||
#include "KinematicsExceptions.h"
|
||||
#include <sstream>
|
||||
|
||||
namespace Mask {
|
||||
|
||||
MassLookup* MassLookup::s_instance = new MassLookup();
|
||||
|
||||
MassLookup::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 {
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
|
@ -18,22 +18,35 @@ Converted to true singleton to simplify usage -- Aug. 2021 GWM
|
|||
|
||||
namespace Mask {
|
||||
|
||||
class MassLookup {
|
||||
class MassLookup
|
||||
{
|
||||
public:
|
||||
~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);
|
||||
|
||||
static MassLookup& GetInstance() {
|
||||
static MassLookup s_instance;
|
||||
return s_instance;
|
||||
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(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() { 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;
|
|
@ -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 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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
bool EnforceDictionaryLinked() { return true; }
|
||||
}
|
59
src/Mask/Nucleus.h
Normal file
59
src/Mask/Nucleus.h
Normal 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
|
|
@ -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 {
|
||||
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
30
src/Mask/OneStepSystem.h
Normal 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
|
|
@ -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() {}
|
||||
}
|
24
src/Mask/RandomGenerator.h
Normal file
24
src/Mask/RandomGenerator.h
Normal 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
|
|
@ -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;
|
||||
void Reaction::SetEjectileThetaType(RxnThetaType type)
|
||||
{
|
||||
if(m_isDecay)
|
||||
return;
|
||||
|
||||
m_eject_theta_type = type;
|
||||
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();
|
||||
|
||||
reactants[2].SetVectorSpherical(m_theta, m_phi, ejectP, ejectE);
|
||||
double ejectP = std::sqrt(ejectKE * (ejectKE + 2.0 * m_ejectile->groundStateMass));
|
||||
double ejectE = ejectKE + m_ejectile->groundStateMass;
|
||||
|
||||
reactants[3] = reactants[0] + reactants[1] - reactants[2];
|
||||
m_ejectile->SetVec4Spherical(m_theta, m_phi, ejectP, ejectE);
|
||||
|
||||
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);
|
||||
m_residual->vec4 = m_target->vec4 + m_projectile->vec4 - m_ejectile->vec4;
|
||||
|
||||
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);
|
||||
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(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:
|
||||
void Reaction::CalculateReaction()
|
||||
{
|
||||
CalculateReactionThetaCM();
|
||||
break;
|
||||
}
|
||||
case lab:
|
||||
switch(m_ejectThetaType)
|
||||
{
|
||||
CalculateReactionThetaLab();
|
||||
break;
|
||||
}
|
||||
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
72
src/Mask/Reaction.h
Normal 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
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
||||
};
|
|
@ -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
|
|
@ -7,25 +7,34 @@
|
|||
*/
|
||||
#include "Stopwatch.h"
|
||||
|
||||
Stopwatch::Stopwatch() {
|
||||
namespace Mask {
|
||||
|
||||
Stopwatch::Stopwatch()
|
||||
{
|
||||
start_time = Clock::now();
|
||||
stop_time = start_time;
|
||||
}
|
||||
|
||||
Stopwatch::~Stopwatch() {}
|
||||
|
||||
void Stopwatch::Start() {
|
||||
void Stopwatch::Start()
|
||||
{
|
||||
start_time = Clock::now();
|
||||
}
|
||||
|
||||
void Stopwatch::Stop() {
|
||||
void Stopwatch::Stop()
|
||||
{
|
||||
stop_time = Clock::now();
|
||||
}
|
||||
|
||||
double Stopwatch::GetElapsedSeconds() {
|
||||
double Stopwatch::GetElapsedSeconds()
|
||||
{
|
||||
return std::chrono::duration_cast<std::chrono::duration<double>>(stop_time-start_time).count();
|
||||
}
|
||||
|
||||
double Stopwatch::GetElapsedMilliseconds() {
|
||||
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
32
src/Mask/Stopwatch.h
Normal 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
|
|
@ -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;
|
||||
MassLookup& masses = MassLookup::GetInstance();
|
||||
eloss.SetTargetComponents(Z, A, Stoich);
|
||||
for(size_t i=0; i<Z.size(); i++)
|
||||
void Target::Init(const std::vector<int>& z, const std::vector<int>& a, const std::vector<int>& stoich)
|
||||
{
|
||||
target_material.add_element(masses.FindMassU(Z[i], A[i]), Z[i], Stoich[i]);
|
||||
m_Z = z;
|
||||
m_A = a;
|
||||
m_stoich = stoich;
|
||||
MassLookup& masses = MassLookup::GetInstance();
|
||||
for(size_t i=0; i<m_Z.size(); 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
};
|
||||
|
|
@ -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();
|
||||
|
||||
}
|
||||
|
||||
|
|
42
src/Mask/ThreeStepSystem.h
Normal file
42
src/Mask/ThreeStepSystem.h
Normal 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
|
|
@ -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];
|
||||
|
||||
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_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
|
||||
|
||||
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()
|
||||
{
|
||||
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::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::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
40
src/Mask/TwoStepSystem.h
Normal 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
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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}
|
||||
)
|
3
src/Plotters/Python/.gitignore
vendored
3
src/Plotters/Python/.gitignore
vendored
|
@ -1,3 +0,0 @@
|
|||
__pycache__
|
||||
|
||||
!.gitignore
|
|
@ -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()
|
|
@ -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
|
|
@ -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()
|
|
@ -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()
|
||||
|
||||
|
||||
|
|
@ -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()
|
|
@ -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;
|
||||
}
|
148
src/Plotters/RootPlotter.cpp
Normal file
148
src/Plotters/RootPlotter.cpp
Normal 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;
|
||||
}
|
||||
}
|
34
src/Plotters/RootPlotter.h
Normal file
34
src/Plotters/RootPlotter.h
Normal 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
14
src/Plotters/main.cpp
Normal 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]);
|
||||
}
|
Loading…
Reference in New Issue
Block a user