/* This file is part of MAUS: http:// micewww.pp.rl.ac.uk:8080/projects/maus * * MAUS is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * MAUS is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with MAUS. If not, see . */ /* Author: Peter Lane */ #include #include #include #include #include #include #include /* #include #include // MAXPATHLEN definition */ #include "gtest/gtest.h" #include "CLHEP/Vector/Rotation.h" #include "CLHEP/Vector/ThreeVector.h" #include "BeamTools/BTTracker.hh" #include "Utils/Exception.hh" #include "src/common_cpp/Globals/GlobalsManager.hh" #include "src/common_cpp/Optics/CovarianceMatrix.hh" #include "src/common_cpp/Optics/PolynomialOpticsModel.hh" #include "src/common_cpp/Optics/PhaseSpaceVector.hh" #include "src/common_cpp/Optics/TransferMap.hh" #include "src/common_cpp/Simulation/MAUSGeant4Manager.hh" #include "src/common_cpp/Simulation/MAUSPhysicsList.hh" #include "src/common_cpp/Simulation/VirtualPlanes.hh" #include "src/common_cpp/Utils/Globals.hh" #include "json/reader.h" #include "json/value.h" using MAUS::PolynomialOpticsModel; Json::Value SetupConfig(int verbose_level); class PolynomialOpticsModelTest : public testing::Test { public: PolynomialOpticsModelTest() : default_virtual_planes_( new MAUS::VirtualPlaneManager(*MAUS::MAUSGeant4Manager::GetInstance() ->GetVirtualPlanes())) { MAUS::MAUSGeant4Manager * simulation = MAUS::MAUSGeant4Manager::GetInstance(); Json::Value * config = MAUS::Globals::GetConfigurationCards(); orig_verbose_level = (*config)["verbose_level"].asInt(); (*config)["verbose_level"] = Json::Value(2); (*config)["reference_physics_processes"] = Json::Value("none"); (*config)["physics_processes"] = Json::Value("none"); (*config)["particle_decay"] = Json::Value(false); simulation->GetPhysicsList()->Setup(); std::stringstream reference_particle_string; reference_particle_string << std::setprecision(1) << "{\"position\":{\"x\":0.0,\"y\":0.0,\"z\":" << kPrimaryPlane << "}," << "\"momentum\":{\"x\":0.0,\"y\":0.0,\"z\":200.0}," << "\"particle_id\":-13,\"energy\":226.1939223,\"time\":0.0," << "\"spin\":{\"x\":0.0,\"y\":-0.0,\"z\":1.0}," << "\"random_seed\":2}"; (*config)["simulation_reference_particle"] = JsonWrapper::StringToJson(reference_particle_string.str()); Json::Value ellipse(Json::objectValue); ellipse["Emittance_T"] = Json::Value(10.0); ellipse["Emittance_L"] = Json::Value(0.01); ellipse["Beta_T"] = Json::Value(650.); ellipse["Beta_L"] = Json::Value(5.); ellipse["Alpha_T"] = Json::Value(0.); ellipse["Alpha_L"] = Json::Value(0.); ellipse["NormalisedAngularMomentum"] = Json::Value(0.); ellipse["Bz"] = Json::Value(0.); (*config)["TransferMapOpticsModel_EllipseDefinition"] = ellipse; Json::Value deltas(Json::objectValue); deltas["t"] = Json::Value(1.0); deltas["E"] = Json::Value(1.0); deltas["x"] = Json::Value(1.0); deltas["Px"] = Json::Value(1.0); deltas["y"] = Json::Value(1.0); deltas["Py"] = Json::Value(1.0); (*config)["TransferMapOpticsModel_Deltas"] = deltas; Json::Value algorithms(Json::arrayValue); algorithms.append(Json::Value("Least Squares")); algorithms.append(Json::Value("Constrained Least Squares")); algorithms.append(Json::Value("Constrained Chi Squared")); algorithms.append(Json::Value("Sweeping Chi Squared")); algorithms.append(Json::Value("Sweeping Chi Squared Variable Walls")); (*config)["PolynomialOpticsModel_algorithms"] = algorithms; (*config)["PolynomialOpticsModel_algorithm"] = Json::Value("Least Squares"); (*config)["PolynomialOpticsModel_order"] = Json::Value(1); std::string config_string = JsonWrapper::JsonToString(*config); MAUS::GlobalsManager::DeleteGlobals(); MAUS::GlobalsManager::InitialiseGlobals(config_string); std::cout << "Globals:" << std::endl << (*MAUS::Globals::GetConfigurationCards()) << std::endl; virtual_planes_ = new MAUS::VirtualPlaneManager(); simulation->SetVirtualPlanes(virtual_planes_); MAUS::VirtualPlane start_plane = MAUS::VirtualPlane::BuildVirtualPlane( CLHEP::HepRotation(), CLHEP::Hep3Vector(0., 0., kPrimaryPlane), -1, true, kPrimaryPlane, BTTracker::z, MAUS::VirtualPlane::ignore, false); virtual_planes_->AddPlane(new MAUS::VirtualPlane(start_plane), NULL); MAUS::VirtualPlane mid_plane = MAUS::VirtualPlane::BuildVirtualPlane( CLHEP::HepRotation(), CLHEP::Hep3Vector(0., 0., kPrimaryPlane+1000.), -1, true, kPrimaryPlane+1000., BTTracker::z, MAUS::VirtualPlane::ignore, false); virtual_planes_->AddPlane(new MAUS::VirtualPlane(mid_plane), NULL); MAUS::VirtualPlane end_plane = MAUS::VirtualPlane::BuildVirtualPlane( CLHEP::HepRotation(), CLHEP::Hep3Vector(0., 0., kPrimaryPlane+2000.), -1, true, kPrimaryPlane+2000., BTTracker::z, MAUS::VirtualPlane::ignore, false); virtual_planes_->AddPlane(new MAUS::VirtualPlane(end_plane), NULL); } ~PolynomialOpticsModelTest() { MAUS::GlobalsManager::DeleteGlobals(); // SetupConfig() is defined in MAUSUnitTest.cc MAUS::GlobalsManager::InitialiseGlobals( JsonWrapper::JsonToString(SetupConfig(orig_verbose_level))); MAUS::MAUSGeant4Manager::GetInstance() ->SetVirtualPlanes(default_virtual_planes_); std::cout << "*** Reset Globals ***" << std::endl; } protected: void ResolveRootDirectory(std::string & str, const std::string & maus_root_dir) { std::string var_name("${MAUS_ROOT_DIR}"); size_t index = str.find(var_name); while (index != std::string::npos) { str.replace(index, var_name.length(), maus_root_dir); index = str.find(var_name, index+var_name.length()); } } static const double kPrimaryPlane; static const double kCovariances[36]; static const MAUS::CovarianceMatrix kCovarianceMatrix; MAUS::VirtualPlaneManager* virtual_planes_; MAUS::VirtualPlaneManager* default_virtual_planes_; int orig_verbose_level; private: }; // ************************************************* // PolynomialOpticsModelTest static const initializations // ************************************************* const double PolynomialOpticsModelTest::kPrimaryPlane = 10; const double PolynomialOpticsModelTest::kCovariances[36] = { 0., 1., 2., 3., 4., 5., 1., 2., 3., 4., 5., 6., 2., 3., 4., 5., 6., 7., 3., 4., 5., 6., 7., 8., 4., 5., 6., 7., 8., 9., 5., 6., 7., 8., 9., 10. }; const MAUS::CovarianceMatrix PolynomialOpticsModelTest::kCovarianceMatrix( PolynomialOpticsModelTest::kCovariances); // *********** // test cases // *********** TEST_F(PolynomialOpticsModelTest, Constructor) { const PolynomialOpticsModel optics_model( MAUS::Globals::GetConfigurationCards()); } /* TEST_F(PolynomialOpticsModelTest, Build) { // Bad build -- incomplete particle tracks Json::Value * config = MAUS::Globals::GetConfigurationCards(); (*config)["reference_physics_processes"] = Json::Value("mean_energy_loss"); (*config)["physics_processes"] = Json::Value("mean_energy_loss"); (*config)["particle_decay"] = Json::Value(true); (*config)["muon_half_life"] = Json::Value(1.0); // 1 ns -> ~25 cm std::string config_string = JsonWrapper::JsonToString(*config); MAUS::GlobalsManager::DeleteGlobals(); MAUS::GlobalsManager::InitialiseGlobals(config_string); PolynomialOpticsModel bad_optics_model_1(config); bool success = false; try { bad_optics_model_1.Build(); } catch (MAUS::Exceptions::Exception exc) { success = true; } EXPECT_TRUE(success); } */ TEST_F(PolynomialOpticsModelTest, Accessors) { PolynomialOpticsModel optics_model( MAUS::Globals::GetConfigurationCards()); double primary_plane = optics_model.primary_plane(); ASSERT_DOUBLE_EQ(kPrimaryPlane, primary_plane); optics_model.set_primary_plane(kPrimaryPlane+1000.); primary_plane = optics_model.primary_plane(); ASSERT_DOUBLE_EQ(kPrimaryPlane+1000., primary_plane); } TEST_F(PolynomialOpticsModelTest, AvailablePositions) { PolynomialOpticsModel optics_model( MAUS::Globals::GetConfigurationCards()); // Bad position query before model is built bool success = false; try { optics_model.GetAvailableMapPositions(); } catch (MAUS::Exceptions::Exception exc) { success = true; } EXPECT_TRUE(success); // One position per virtual detectors optics_model.Build(); const std::vector positions = optics_model.GetAvailableMapPositions(); const size_t position_count = positions.size(); // start, mid, and end virtual detectors EXPECT_EQ(position_count, static_cast(3)); } TEST_F(PolynomialOpticsModelTest, Transport) { PolynomialOpticsModel optics_model( MAUS::Globals::GetConfigurationCards()); // The configuration specifies a 2m drift between 1m and 3m. optics_model.Build(); // Check transport to start plane MAUS::PhaseSpaceVector input_vector(0., 226., 1., 0., 3., 0.); MAUS::PhaseSpaceVector output_vector = optics_model.Transport(input_vector, kPrimaryPlane); for (int index = 0; index < 6; ++index) { EXPECT_NEAR(input_vector[index], output_vector[index], 5.0e-4); } MAUS::CovarianceMatrix output_errors = optics_model.Transport(kCovarianceMatrix, kPrimaryPlane); for (int row = 1; row <= 6; ++row) { for (int column = 1; column <= 6; ++column) { EXPECT_NEAR(kCovarianceMatrix(row, column), output_errors(row, column), 5.0e-4); } } // Check transport to end plane MAUS::PhaseSpaceVector expected_vector(7.5466, 226., 1., 0., 3., 0.); output_vector = optics_model.Transport(input_vector, kPrimaryPlane+2000.); for (int index = 0; index < 6; ++index) { EXPECT_NEAR(expected_vector[index], output_vector[index], 5.0e-4); } // Check transport to mid plane expected_vector = MAUS::PhaseSpaceVector(3.7733, 226., 1., 0., 3., 0.); output_vector = optics_model.Transport(input_vector, kPrimaryPlane+1000.); for (int index = 0; index < 6; ++index) { EXPECT_NEAR(expected_vector[index], output_vector[index], 5.0e-4); } // Check transport from mid plane to end plane (should fail because the // Inverse() function in PolynomialMap is not implemented) bool transport_failed = false; try { output_vector = optics_model.Transport(input_vector, kPrimaryPlane+1000., kPrimaryPlane+2000.); } catch (MAUS::Exceptions::Exception exc) { transport_failed = true; } EXPECT_TRUE(transport_failed); } /* This test fails, but higher order maps should be more accurate. * TEST_F(PolynomialOpticsModelTest, SecondOrderTransport) { // Test higher order polynomial map transport to end plane Json::Value * config = MAUS::Globals::GetConfigurationCards(); (*config)["PolynomialOpticsModel_order"] = Json::Value(2); std::string config_string = JsonWrapper::JsonToString(*config); MAUS::GlobalsManager::DeleteGlobals(); MAUS::GlobalsManager::InitialiseGlobals(config_string); PolynomialOpticsModel optics_model(*config); optics_model.Build(); MAUS::PhaseSpaceVector input_vector(0., 226., 1., 0., 3., 0.); MAUS::PhaseSpaceVector expected_vector(7.5466, 226., 1., 0., 3., 0.); MAUS::PhaseSpaceVector output_vector = optics_model.Transport(input_vector, 1000.); for (int index = 0; index < 6; ++index) { EXPECT_NEAR(expected_vector[index], output_vector[index], 5.0e-4); } } */ TEST_F(PolynomialOpticsModelTest, UnsupportedAlgorithms) { // Make sure unsupported algorithms throw exceptions std::vector algorithms; algorithms.push_back(std::string("Constrained Least Squares")); algorithms.push_back(std::string("Constrained Chi Squared")); algorithms.push_back(std::string("Sweeping Chi Squared")); algorithms.push_back(std::string("Sweeping Chi Squared Variable Walls")); Json::Value * config = MAUS::Globals::GetConfigurationCards(); (*config)["PolynomialOpticsModel_order"] = Json::Value(1); for (std::vector::const_iterator iter = algorithms.begin(); iter < algorithms.end(); ++iter) { (*config)["PolynomialOpticsModel_algorithm"] = Json::Value(*iter); PolynomialOpticsModel optics_model(config); optics_model.Build(); EXPECT_EQ(optics_model.GetAvailableMapPositions().size(), 0); } }