1
/* This file is part of MAUS: http://micewww.pp.rl.ac.uk/projects/maus
3
* MAUS is free software: you can redistribute it and/or modify
4
* it under the terms of the GNU General Public License as published by
5
* the Free Software Foundation, either version 3 of the License, or
6
* (at your option) any later version.
8
* MAUS is distributed in the hope that it will be useful,
9
* but WITHOUT ANY WARRANTY; without even the implied warranty of
10
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
* GNU General Public License for more details.
13
* You should have received a copy of the GNU General Public License
14
* along with MAUS. If not, see <http://www.gnu.org/licenses/>.
18
#include "gtest/gtest.h"
20
#include "src/common_cpp/Simulation/MAUSGeant4Manager.hh"
21
#include "src/common_cpp/Utils/Globals.hh"
22
// #define wrapper for friend declarations
23
#define TESTS_CPP_UNIT_SIMULATION_DETECTORCONSTRUCTORTEST_CC
24
#include "src/common_cpp/Simulation/DetectorConstruction.hh"
25
#undef TESTS_CPP_UNIT_SIMULATION_DETECTORCONSTRUCTORTEST_CC
27
// Comment out functions due to memory problem/instability in G4
30
namespace Simulation {
31
// Detector construction is pretty untestable because it is all wrapped up in
33
class DetectorConstructionTest : public ::testing::Test {
35
DetectorConstructionTest() {
36
dc = Globals::GetInstance()->GetGeant4Manager()->GetGeometry();
37
mod_path = std::string(getenv("MAUS_ROOT_DIR"))+
38
"/tests/cpp_unit/Simulation/TestGeometries/";
45
~DetectorConstructionTest() {
46
MiceModule mod("Test.dat");
47
dc->SetMiceModules(mod);
53
MAUSPrimaryGeneratorAction::PGParticle p;
54
DetectorConstruction* dc;
59
void SetStepperType(DetectorConstruction* dc, std::string type) {
60
Json::Value& cards = *(Globals::GetInstance()->GetConfigurationCards());
61
cards["stepping_algorithm"] = Json::Value(type);
62
dc->SetDatacardVariables(cards);
65
TEST_F(DetectorConstructionTest, SetSteppingAlgorithmTest) {
66
MiceModule modEM(mod_path+"EMFieldTest.dat");
67
MiceModule modMag(mod_path+"MagFieldTest.dat");
68
std::string models[] = {"ClassicalRK4", "Classic", "SimpleHeum",
69
"ImplicitEuler", "SimpleRunge", "ExplicitEuler", "CashKarpRKF45"};
70
// I just check the default - it is too slow to test everything
71
for (int i = 0; i < 1; ++i) {
72
SetStepperType(dc, models[i]);
73
dc->SetMiceModules(modEM);
75
SetStepperType(dc, "error");
76
EXPECT_THROW(dc->SetMiceModules(modMag), MAUS::Exception);
77
for (int i = 0; i < 1; ++i) {
78
SetStepperType(dc, models[i]);
79
dc->SetMiceModules(modMag);
81
SetStepperType(dc, "error");
82
EXPECT_THROW(dc->SetMiceModules(modMag), MAUS::Exception);
83
SetStepperType(dc, "ClassicalRK4");
89
TEST_F(DetectorConstructionTest, RootVolumeTest) {
90
// I dont test anywhere that the volume name is updated. I dont know how
91
MiceModule mod(mod_path+"RootVolumeTest.dat");
92
dc->SetMiceModules(mod);
93
// Check that root volume gets correct size - tracks end on boundary edge
94
// Check that user limits were set - track has (size/step_size)+1 steps
95
Json::Value out = Globals::GetInstance()->GetGeant4Manager()->RunParticle(p);
96
double z_end = out["tracks"][Json::Value::UInt(0)]["final_position"]["z"].asDouble();
97
EXPECT_DOUBLE_EQ(z_end, 3000.);
98
EXPECT_EQ(out["tracks"][Json::Value::UInt(0)]["steps"].size(), size_t(4));
101
out = Globals::GetInstance()->GetGeant4Manager()->RunParticle(p);
102
double x_end = out["tracks"][Json::Value::UInt(0)]["final_position"]["x"].asDouble();
103
EXPECT_DOUBLE_EQ(x_end, 1000.);
104
EXPECT_EQ(out["tracks"][Json::Value::UInt(0)]["steps"].size(), size_t(2));
107
out = Globals::GetInstance()->GetGeant4Manager()->RunParticle(p);
108
double y_end = out["tracks"][Json::Value::UInt(0)]["final_position"]["y"].asDouble();
109
EXPECT_DOUBLE_EQ(y_end, 2000.);
110
EXPECT_EQ(out["tracks"][Json::Value::UInt(0)]["steps"].size(), size_t(3));
111
// check that no energy deposited in vacuum
112
Json::Value steps = out["tracks"][Json::Value::UInt(0)]["steps"];
113
double edep = steps[Json::Value::UInt(0)]["energy_deposited"].asDouble();
114
EXPECT_LT(edep, 1e-9);
117
TEST_F(DetectorConstructionTest, RootVolumeTestMaterial) {
118
MiceModule mod(mod_path+"RootVolumeTestMaterial.dat");
119
dc->SetMiceModules(mod);
120
// roughly minimum ionising
121
// eloss = 11 MeV in 350 mm
123
Json::Value out = Globals::GetInstance()->GetGeant4Manager()->RunParticle(p);
124
Json::Value steps = out["tracks"][Json::Value::UInt(0)]["steps"];
125
double edep = steps[Json::Value::UInt(0)]["energy_deposited"].asDouble();
126
double path = steps[Json::Value::UInt(0)]["path_length"].asDouble();
127
// actual value should be around 0.03; I don't want to check the physics
128
// just that it is reasonable (i.e. a material is applied)
129
// Note we also check Galactic has no energy loss in RootVolumeTest
130
EXPECT_GT(edep/path, 0.01);
131
EXPECT_LT(edep/path, 0.1);
134
TEST_F(DetectorConstructionTest, NormalVolumePlacementTest) {
135
// Check rotation and translations
136
MiceModule mod(mod_path+"VolumeTestPlacement.dat");
137
dc->SetMiceModules(mod);
138
Json::Value out = Globals::GetInstance()->GetGeant4Manager()->RunParticle(p);
139
Json::Value steps = out["tracks"][Json::Value::UInt(0)]["steps"];
140
EXPECT_EQ(steps.size(), 4);
141
EXPECT_DOUBLE_EQ(steps[Json::Value::UInt(0)]["position"]["z"].asDouble(),
143
EXPECT_DOUBLE_EQ(steps[Json::Value::UInt(1)]["position"]["z"].asDouble(),
145
EXPECT_DOUBLE_EQ(steps[Json::Value::UInt(2)]["position"]["z"].asDouble(),
147
EXPECT_DOUBLE_EQ(steps[Json::Value::UInt(3)]["position"]["z"].asDouble(),
151
TEST_F(DetectorConstructionTest, NormalVolumeMaterialTest) {
153
MiceModule mod(mod_path+"VolumeTestMaterial.dat");
154
dc->SetMiceModules(mod);
156
Json::Value out = Globals::GetInstance()->GetGeant4Manager()->RunParticle(p);
157
Json::Value steps = out["tracks"][Json::Value::UInt(0)]["steps"];
158
double edep = steps[Json::Value::UInt(2)]["energy_deposited"].asDouble();
159
double path = steps[Json::Value::UInt(2)]["path_length"].asDouble()-
160
steps[Json::Value::UInt(1)]["path_length"].asDouble();
161
EXPECT_GT(edep/path, 0.01);
162
EXPECT_LT(edep/path, 0.1);
166
TEST_F(DetectorConstructionTest, NormalVolumeUserLimitsTest) {
168
MiceModule mod(mod_path+"VolumeTestUserLimits.dat");
169
dc->SetMiceModules(mod);
171
// start and end of track same - due to kinetic energy threshold
172
// beware kinetic_energy_threshold datacard = 0.1
173
p.energy = sqrt(5.*5.+105.658*105.658); // KE = 0.12
175
out = Globals::GetInstance()->GetGeant4Manager()->RunParticle(p);
176
Json::Value start = out["tracks"][Json::Value::UInt(0)]["initial_position"];
177
Json::Value final = out["tracks"][Json::Value::UInt(0)]["final_position"];
178
EXPECT_DOUBLE_EQ(start["z"].asDouble(), final["z"].asDouble());
180
// two steps (three step points) ending at track max time (40 ps)
181
p.energy = sqrt(15.*15.+105.658*105.658); // KE = 1.05 on time limiter
182
out = Globals::GetInstance()->GetGeant4Manager()->RunParticle(p);
183
double time = out["tracks"][Json::Value::UInt(0)]["steps"]
184
[Json::Value::UInt(2)]["time"].asDouble();
185
EXPECT_DOUBLE_EQ(time, 0.04);
187
// two steps (three step points) each 1 mm, ending at track max (2 mm)
188
p.energy = sqrt(1e6*1e6+105.658*105.658); // on step length limiter
189
out = Globals::GetInstance()->GetGeant4Manager()->RunParticle(p);
190
double dz1 = out["tracks"][Json::Value::UInt(0)]["steps"]
191
[Json::Value::UInt(1)]["position"]["z"].asDouble();
192
EXPECT_DOUBLE_EQ(dz1, 1.);
193
double dz2 = out["tracks"][Json::Value::UInt(0)]["steps"]
194
[Json::Value::UInt(2)]["position"]["z"].asDouble();
195
EXPECT_DOUBLE_EQ(dz2, 2.);
196
double dzTrack = out["tracks"][Json::Value::UInt(0)]["final_position"]
198
EXPECT_DOUBLE_EQ(dzTrack, 2.);
201
TEST_F(DetectorConstructionTest, NormalVolumeVisTest) {
202
// Check that vis doesnt blow up (what else to do?)
203
MiceModule mod(mod_path+"VolumeTestVisAtt.dat");
204
dc->SetMiceModules(mod);
207
TEST_F(DetectorConstructionTest, NormalVolumeNoneRecursionTest) {
208
// Check that recursion through MiceModules does throw an exception
209
MiceModule mod(mod_path+"VolumeTestNone.dat");
210
bool cout_alive = Squeak::coutIsActive();
211
EXPECT_THROW(dc->SetMiceModules(mod), MAUS::Exception);
212
EXPECT_EQ(Squeak::coutIsActive(), cout_alive);
215
TEST_F(DetectorConstructionTest, BuildSensitiveDetectorTest) {
216
MiceModule mod(mod_path+"SDTest.dat");
217
dc->SetMiceModules(mod);
218
EXPECT_EQ(dc->GetSDSize(), 3);
219
for (int i = 0; i < dc->GetSDSize(); ++i)
220
EXPECT_EQ(dc->GetSDHits(i).size(), size_t(0));
221
MAUSPrimaryGeneratorAction::PGParticle p;
226
Json::Value out = Globals::GetInstance()->GetGeant4Manager()->RunParticle(p);
227
for (int i = 0; i < dc->GetSDSize(); ++i) {
228
EXPECT_GT(dc->GetSDHits(i).size(), size_t(0));
231
for (int i = 0; i < dc->GetSDSize(); ++i) {
232
EXPECT_EQ(dc->GetSDHits(i).size(), size_t(0));
234
EXPECT_THROW(dc->GetSDHits(dc->GetSDSize()), MAUS::Exception);
236
MiceModule mod_error(mod_path+"SDErrorTest.dat");
237
EXPECT_THROW(dc->SetMiceModules(mod_error), MAUS::Exception);
240
TEST_F(DetectorConstructionTest, SetDatacardVariablesTest) {
241
// nothing terribly productive to test
244
TEST_F(DetectorConstructionTest, BuildG4DetectorVolumeTest) {
245
MiceModule mod(mod_path+"G4DetectorTest.dat");
246
dc->SetMiceModules(mod);
247
MiceModule modError(mod_path+"G4DetectorTestError.dat");
248
EXPECT_THROW(dc->SetMiceModules(modError), MAUS::Exception);