/* 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 .
*
*/
#include
#include
#include "Geant4/G4Track.hh"
#include "Geant4/G4Step.hh"
#include "Geant4/G4StepPoint.hh"
#include "json/json.h"
#include "src/legacy/Config/MiceModule.hh"
#include "Utils/Exception.hh"
#include "src/legacy/BeamTools/BTField.hh"
#include "src/legacy/BeamTools/BTTracker.hh"
#include "src/common_cpp/DataStructure/ThreeVector.hh"
#include "src/common_cpp/Simulation/VirtualPlanes.hh"
#include "src/common_cpp/Simulation/MAUSGeant4Manager.hh"
namespace MAUS {
VirtualPlane::stepping VirtualPlane::_stepping = VirtualPlane::integrate;
/////////////////////// VirtualPlane //////////////////
VirtualPlane::VirtualPlane() {
_planeType = BTTracker::z;
_step = 0.1;
_position = CLHEP::Hep3Vector(0., 0., 0.);
_rotation = CLHEP::HepRotation();
_radialExtent = -1;
_independentVariable = 0.;
_globalCoordinates = false;
_multipass = VirtualPlane::ignore;
}
VirtualPlane::VirtualPlane(const VirtualPlane& rhs)
: _planeType(rhs._planeType), _independentVariable(rhs._independentVariable),
_step(rhs._step), _radialExtent(rhs._radialExtent),
_globalCoordinates(rhs._globalCoordinates), _multipass(rhs._multipass),
_position(rhs._position), _rotation(rhs._rotation),
_allowBackwards(rhs._allowBackwards) {
}
VirtualPlane VirtualPlane::BuildVirtualPlane(CLHEP::HepRotation rot,
CLHEP::Hep3Vector pos, double radialExtent,
bool globalCoordinates, double indie,
BTTracker::var type, multipass_handler pass,
bool allowBackwards) {
VirtualPlane vp;
vp._planeType = type;
vp._position = pos;
vp._rotation = rot;
vp._independentVariable = indie;
vp._radialExtent = radialExtent;
vp._globalCoordinates = globalCoordinates;
vp._multipass = pass;
vp._allowBackwards = allowBackwards;
if (type != BTTracker::tau_field && type != BTTracker::u &&
type != BTTracker::z && type != BTTracker::t) {
throw(Exception(Exception::recoverable,
"Virtual plane type not implemented",
"VirtualPlane::BuildVirtualPlane(...)"));
}
return vp;
}
bool VirtualPlane::SteppingOver(const G4Step* aStep) const {
double pre = GetIndependentVariable(aStep->GetPreStepPoint());
double post = GetIndependentVariable(aStep->GetPostStepPoint());
if (pre <= _independentVariable && post > _independentVariable) {
return true; // stepping forwards
}
if (_allowBackwards && post <= _independentVariable &&
pre > _independentVariable) {
return true; // stepping backwards
}
return false;
}
void VirtualPlane::FillStaticData
(MAUS::VirtualHit * aHit, const G4Step * aStep) const {
G4Track * theTrack = aStep->GetTrack();
aHit->SetTrackId(theTrack->GetTrackID());
aHit->SetParticleId(theTrack->GetDynamicParticle()
->GetDefinition()->GetPDGEncoding());
aHit->SetMass(theTrack->GetDynamicParticle()->GetMass());
aHit->SetCharge(theTrack->GetDynamicParticle()->GetCharge());
}
void VirtualPlane::FillBField(MAUS::VirtualHit * aHit, const G4Step * aStep) const {
double point[4] =
{aHit->GetPosition()[0], aHit->GetPosition()[1], aHit->GetPosition()[2], aHit->GetTime()};
double field[6] = {0., 0., 0., 0., 0., 0.};
GetField()->GetFieldValue(point, field);
aHit->SetBField(MAUS::ThreeVector(field[0], field[1], field[2]));
aHit->SetEField(MAUS::ThreeVector(field[3], field[4], field[5]));
}
bool VirtualPlane::InRadialCut(CLHEP::Hep3Vector position) const {
CLHEP::Hep3Vector point = _rotation*(position - _position);
if (point[0]*point[0] + point[1]*point[1] > _radialExtent*_radialExtent &&
_radialExtent > 0.)
return false;
return true;
}
void VirtualPlane::FillKinematics
(MAUS::VirtualHit * aHit, const G4Step * aStep) const {
double x[12];
double* x_from_beginning = NULL;
double* x_from_end = NULL;
switch (_stepping) {
case integrate: {
x_from_beginning = Integrate(aStep->GetPreStepPoint());
x_from_end = Integrate(aStep->GetPostStepPoint());
break;
}
case linear_interpolate:
{
x_from_beginning = ExtractPointData(aStep->GetPreStepPoint());
x_from_end = ExtractPointData(aStep->GetPostStepPoint());
break;
}
}
double indep_beg = GetIndependentVariable(aStep->GetPreStepPoint());
double indep_end = GetIndependentVariable(aStep->GetPostStepPoint());
for (int i = 0; i < 12; i++)
x[i] = (x_from_end[i]-x_from_beginning[i])/(indep_end-indep_beg)
*(_independentVariable-indep_beg)+x_from_beginning[i];
aHit->SetPosition(MAUS::ThreeVector(x[1], x[2], x[3]));
aHit->SetMomentum(MAUS::ThreeVector(x[5], x[6], x[7]));
aHit->SetSpin(MAUS::ThreeVector(x[8], x[9], x[10]));
double mass = aStep->GetPostStepPoint()->GetMass();
// FORCE mass shell condition
x[4] = ::sqrt(x[5]*x[5]+x[6]*x[6]+x[7]*x[7]+mass*mass);
aHit->SetTime(x[0]);
aHit->SetProperTime(0.);
aHit->SetPathLength(0.);
delete [] x_from_beginning;
delete [] x_from_end;
if (!InRadialCut(CLHEP::Hep3Vector(x[1], x[2], x[3])))
throw(Exception(Exception::recoverable, "Hit outside radial cut", // appropriate?
"VirtualPlane::FillKinematics"));
}
void VirtualPlane::TransformToLocalCoordinates(VirtualHit* aHit) const {
::CLHEP::Hep3Vector pos = MAUSToCLHEP(aHit->GetPosition());
::CLHEP::Hep3Vector pos_rot = _rotation*(pos - _position);
aHit->SetPosition(CLHEPToMAUS(pos_rot));
::CLHEP::Hep3Vector mom = MAUSToCLHEP(aHit->GetMomentum());
::CLHEP::Hep3Vector mom_rot = _rotation*mom;
aHit->SetMomentum(CLHEPToMAUS(mom_rot));
::CLHEP::Hep3Vector bfield = MAUSToCLHEP(aHit->GetBField());
::CLHEP::Hep3Vector bfield_rot = _rotation*bfield;
aHit->SetBField(CLHEPToMAUS(bfield_rot));
::CLHEP::Hep3Vector efield = MAUSToCLHEP(aHit->GetEField());
::CLHEP::Hep3Vector efield_rot = _rotation*efield;
aHit->SetEField(CLHEPToMAUS(efield_rot));
}
double VirtualPlane::GetIndependentVariable(G4StepPoint* aPoint) const {
switch (_planeType) {
case BTTracker::z: return aPoint->GetPosition()[2];
case BTTracker::t: return aPoint->GetGlobalTime();
case BTTracker::tau_field: return aPoint->GetProperTime();
case BTTracker::u:
return ( _rotation*(aPoint->GetPosition() - _position) )[2];
default: return 0.;
}
}
double * VirtualPlane::ExtractPointData(G4StepPoint *aPoint) const {
double* x_in = new double[12];
for (int i = 0; i < 3; i++) {
x_in[i+1] = aPoint->GetPosition()[i];
x_in[i+5] = aPoint->GetMomentum()[i];
x_in[i+8] = aPoint->GetPolarization()[i];
}
x_in[0] = aPoint->GetGlobalTime();
x_in[4] = aPoint->GetTotalEnergy();
return x_in;
}
double * VirtualPlane::Integrate(G4StepPoint* aPoint) const {
double* x_in = ExtractPointData(aPoint);
double step = _step;
if (GetIndependentVariable(aPoint) > _independentVariable) step *= -1.;
BTTracker::integrate(_independentVariable, x_in, GetField(), _planeType, step,
aPoint->GetCharge(), _position, _rotation);
return x_in;
}
VirtualHit VirtualPlane::BuildNewHit(const G4Step * aStep, int station) const {
VirtualHit aHit;
FillStaticData(&aHit, aStep);
FillKinematics(&aHit, aStep);
FillBField(&aHit, aStep);
aHit.SetStationId(station);
if (!_globalCoordinates) TransformToLocalCoordinates(&aHit);
return aHit;
}
const BTField* VirtualPlane::GetField() const {
return reinterpret_cast
(MAUSGeant4Manager::GetInstance()->GetField());
}
::CLHEP::Hep3Vector VirtualPlane::MAUSToCLHEP(MAUS::ThreeVector value) {
return ::CLHEP::Hep3Vector(value[0], value[1], value[2]);
}
MAUS::ThreeVector VirtualPlane::CLHEPToMAUS(::CLHEP::Hep3Vector value) {
return MAUS::ThreeVector(value[0], value[1], value[2]);
}
//////////////////////// VirtualPlaneManager //////////////////////////
VirtualPlaneManager::VirtualPlaneManager()
: _useVirtualPlanes(false), _planes(), _mods(), _nHits(0),
_hits(NULL) {
StartOfEvent();
}
VirtualPlaneManager::~VirtualPlaneManager() {
_useVirtualPlanes = false;
_nHits = std::vector();
_mods = std::map();
for (size_t i = 0; i < _planes.size(); ++i)
delete _planes[i];
_planes = std::vector();
if (_hits != NULL)
delete _hits;
_hits = NULL;
}
VirtualPlaneManager::VirtualPlaneManager(VirtualPlaneManager& rhs)
: _useVirtualPlanes(rhs._useVirtualPlanes), _planes(), _mods(),
_nHits(rhs._nHits), _hits(NULL) {
if (rhs._hits != NULL) {
_hits = new std::vector(rhs._hits->size());
for (size_t i = 0; i < rhs._hits->size(); ++i) {
_hits[i] = rhs._hits[i];
}
}
for (size_t i = 0; i < rhs._planes.size(); ++i) {
_planes.push_back(new VirtualPlane(*rhs._planes[i]));
_mods[_planes[i]] = rhs._mods[rhs._planes[i]];
}
}
// Point here is if I go round e.g. a ring, station number should be
// (number_of_passes * number_of_stations) + i
void VirtualPlaneManager::VirtualPlanesSteppingAction
(const G4Step* aStep) {
if (!_useVirtualPlanes) return;
for (unsigned int i = 0; i < _planes.size(); i++)
try {
if (_planes[i]->SteppingOver(aStep)) {
VirtualPlane::multipass_handler mp =
_planes[i]->GetMultipassAlgorithm();
if (_nHits[i]>0) {
if (mp == VirtualPlane::new_station) {
_hits->push_back(_planes[i]->BuildNewHit(aStep,
_planes.size()*_nHits[i]+i+1));
_nHits[i]++;
}
if (mp == VirtualPlane::same_station) {
_hits->push_back(_planes[i]->BuildNewHit(aStep, i+1));
_nHits[i]++;
}
} else {
_hits->push_back(_planes[i]->BuildNewHit(aStep, i+1));
_nHits[i]++;
}
}
} catch (Exception exc) {} // do nothing - just dont make a hit
}
void VirtualPlaneManager::SetVirtualHits(std::vector* hits) {
if (_hits != NULL)
delete _hits;
_hits = hits;
}
std::vector* VirtualPlaneManager::TakeVirtualHits() {
std::vector* hits_tmp = _hits;
_hits = NULL;
return hits_tmp;
}
void VirtualPlaneManager::StartOfEvent() {
_nHits = std::vector(_planes.size(), 0);
SetVirtualHits(new std::vector());
}
void VirtualPlaneManager::ConstructVirtualPlanes
(MiceModule* model) {
std::vector modules =
model->findModulesByPropertyString("SensitiveDetector", "Virtual");
std::vector envelopes =
model->findModulesByPropertyString("SensitiveDetector", "Envelope");
modules.insert(modules.end(), envelopes.begin(), envelopes.end());
for (unsigned int i = 0; i < modules.size(); i++) {
AddPlane(new VirtualPlane(ConstructFromModule(modules[i])), modules[i]);
}
}
VirtualPlane VirtualPlaneManager::ConstructFromModule(const MiceModule* mod) {
std::string variable = "z";
double radialExtent = -1.;
double indie = 0.;
bool globalCoordinates = true;
bool allowBackwards = true;
if (mod->propertyExistsThis("IndependentVariable", "string"))
variable = mod->propertyStringThis("IndependentVariable");
if (mod->propertyExistsThis("RadialExtent", "double"))
radialExtent = mod->propertyDoubleThis("RadialExtent");
if (mod->propertyExistsThis("GlobalCoordinates", "bool"))
globalCoordinates = mod->propertyBoolThis("GlobalCoordinates");
VirtualPlane::multipass_handler pass = VirtualPlane::ignore;
if (mod->propertyExistsThis("MultiplePasses", "string")) {
std::string m_pass = mod->propertyString("MultiplePasses");
/**/ if (m_pass == "Ignore") pass = VirtualPlane::ignore;
else if (m_pass == "SameStation") pass = VirtualPlane::same_station;
else if (m_pass == "NewStation") pass = VirtualPlane::new_station;
else
throw(Exception(Exception::recoverable,
"Did not recognise MultiplePasses option "+m_pass,
"VirtualPlaneManager::ConstructFromModule") );
}
if (mod->propertyExistsThis("AllowBackwards", "bool"))
allowBackwards = mod->propertyBoolThis("AllowBackwards");
BTTracker::var var_enum = BTTracker::z;
for (unsigned int i = 0; i < variable.size(); i++)
variable[i] = tolower(variable[i]);
if (variable == "time" || variable == "t") {
indie = mod->propertyDoubleThis("PlaneTime");
var_enum = BTTracker::t;
} else if (variable == "tau") {
indie = mod->propertyDoubleThis("PlaneTime");
var_enum = BTTracker::tau_field;
} else if (variable == "z") {
indie = mod->globalPosition()[2];
var_enum = BTTracker::z;
} else if (variable == "u") {
var_enum = BTTracker::u;
} else {
throw(Exception(Exception::recoverable,
"Did not recognise IndependentVariable in Virtual detector module "+
mod->fullName(),
"VirtualPlaneManager::ConstructFromModule"));
}
return VirtualPlane::BuildVirtualPlane(mod->globalRotation(),
mod->globalPosition(), radialExtent, globalCoordinates,
indie, var_enum, pass, allowBackwards);
}
void VirtualPlaneManager::AddPlane
(VirtualPlane* newPlane, const MiceModule* mod) {
_planes.push_back(newPlane);
_mods[newPlane] = mod;
sort(_planes.begin(), _planes.end(), VirtualPlane::ComparePosition);
_useVirtualPlanes = _planes.size() > 0;
_nHits = std::vector(_planes.size(), 0);
}
const MiceModule* VirtualPlaneManager::GetModuleFromStationNumber
(int stationNumber) {
return _mods[ PlaneFromStation(stationNumber) ];
}
int VirtualPlaneManager::GetStationNumberFromModule(const MiceModule* module) {
if (_planes.size() == 0)
throw(Exception(Exception::recoverable,
"No Virtual planes initialised",
"VirtualPlaneManager::GetStationNumberFromModule"));
VirtualPlane* plane = NULL;
typedef std::map::iterator map_it;
for (map_it it = _mods.begin(); it != _mods.end() && plane == NULL; it++)
if (it->second == module) plane = it->first; // find plane from module
if (plane == NULL) {
throw(Exception(Exception::recoverable,
"Module "+module->name()+" not found in VirtualPlaneManager",
"VirtualPlaneManager::GetStationNumberFromModule"));
}
for (size_t i = 0; i < _planes.size(); i++)
if (plane == _planes[i]) return i+1; // find station from plane
throw(Exception(Exception::recoverable,
"Module "+module->name()+" not found in VirtualPlaneManager",
"VirtualPlaneManager::GetStationNumberFromModule"));
}
int VirtualPlaneManager::GetNumberOfHits(int stationNumber) {
if (stationNumber-1 >= static_cast(_nHits.size()) ||
stationNumber-1 < 0)
throw(Exception(
Exception::recoverable,
"Station number out of range",
"VirtualPlaneManager::GetNumberOfHits"));
return _nHits[stationNumber-1];
}
VirtualPlane* VirtualPlaneManager::PlaneFromStation(int stationNumber) {
if (_planes.size() == 0)
throw(Exception(Exception::recoverable, "No Virtual planes initialised",
"VirtualPlaneManager::PlaneFromStation()"));
if (stationNumber < 1)
throw(Exception(Exception::recoverable,
"Station number must be > 0",
"VirtualPlaneManager::PlaneFromStation"));
// map from module name to _planes index; if stationNumber > planes.size, it
// means we've gone round twice or more, subtract off
while (stationNumber > static_cast(_planes.size()))
stationNumber -= static_cast(_planes.size());
return _planes[stationNumber-1];
}
void VirtualPlaneManager::RemovePlanes(std::set station) {
std::set targets;
std::set::iterator it1;
for (it1 = station.begin(); it1 != station.end(); ++it1)
targets.insert(PlaneFromStation(*it1));
std::set::iterator it2;
for (it2 = targets.begin(); it2 != targets.end(); ++it2)
RemovePlane(*it2);
}
void VirtualPlaneManager::RemovePlane(VirtualPlane* plane) {
std::vector::iterator it =
std::find(_planes.begin(), _planes.end(), plane);
_planes.erase(it);
_mods.erase(plane);
sort(_planes.begin(), _planes.end(), VirtualPlane::ComparePosition);
_useVirtualPlanes = _planes.size() > 0;
_nHits = std::vector(_planes.size(), 0);
delete plane;
}
}