#ifndef _HBEAM_H_
#define _HBEAM_H_
#include "TString.h"
#include "TVector3.h"
#include "TRandom.h"
#include "TF1.h"
#include "TMath.h"
#include "TArrayD.h"
#include "TObject.h"
#include <sstream>
#include <iostream>
#include <iomanip>
#include <fstream>
using namespace std;
class HBeamElement : public TObject {
public:
TString fName;
Double_t fDistance;
Int_t fId;
Double_t Tij [5][5];
Double_t Tijk[5][5][5];
Double_t fout[5];
Double_t fxCut;
Double_t fyCut;
Int_t fCutType;
Long64_t fCtAll ;
Long64_t fCtFail;
Bool_t fAccepted;
HBeamElement(TString n="not_set",Double_t dist = 0, Int_t id=-1)
{
fName = n;
fDistance = dist;
fId = id;
fCutType = 1;
fxCut = 60;
fyCut = 60;
fCtAll = 0;
fCtFail = 0;
fAccepted = kTRUE;
clear();
}
void setElement(TString name,Int_t cuttype,Double_t xcut,Double_t ycut){
if(name.CompareTo("")!=0) fName = name;
fCutType = cuttype;
fxCut = xcut;
fyCut = ycut;
}
void clear()
{
for(Int_t i = 0; i < 5; i ++) {
fout[i] = 0;
for(Int_t j = 0; j < 5; j ++){
Tij[i][j] =0;
for(Int_t k = 0; k < 5; k ++){
Tijk[i][j][k] = 0;
}
}
}
}
void printTij()
{
for(Int_t i = 0; i < 5; i ++) {
for(Int_t j = 0; j < 5; j ++){
cout<<setw(12)<<Tij[i][j]<<" "<<flush;
}
cout<<endl;
}
}
void printTijk()
{
for(Int_t i = 0; i < 5; i ++) {
for(Int_t k = 0; k < 5; k ++){
for(Int_t j = 0; j <= k; j ++){
cout<<setw(12)<<Tijk[i][j][k]<<" "<<flush;
}
cout<<endl;
}
cout<<endl;
}
}
void print(Bool_t printAll = kFALSE)
{
cout<<"---------------------------------"<<endl;
cout<<"ID : "<<setw(3)<<fId<<" , "<<fName.Data()<<endl;
cout<<"distance : "<<setw(12)<<fDistance<<endl;
cout<<"CutType : "<<setw(3)<<fCutType<<" , x : "<<setw(12)<<fxCut<<", y : "<<setw(12)<<fyCut<<endl;
cout<<"Acceptance : "<<setw(8)<<fCtAll<<" , Failed : "<<setw(8)<<fCtFail<<" , "<<setw(8)<<(fCtAll > 0? (fCtFail/(Double_t)fCtAll)*100: 100)<<" %"<<endl;
if(printAll){
cout<<"first order transform:"<<endl;
printTij();
cout<<"second order transform:"<<endl;
printTijk();
}
}
Bool_t isInAcceptance()
{
if(fCutType == 0 || fCutType > 2) return kTRUE;
if(fCutType == 1 ){
Double_t radius = TMath::Sqrt(fout[0] * fout[0] + fout[2] * fout[2]) ;
if(radius < fxCut ) return kTRUE;
else return kFALSE;
}
if(fCutType == 2 ){
if(TMath::Abs(fout[0]) < fxCut && TMath::Abs(fout[2]) < fyCut ) return kTRUE;
else return kFALSE;
}
return kTRUE;
}
void check()
{
if(!isInAcceptance()) {
fCtFail++;
fAccepted = kFALSE;
} else fAccepted = kTRUE;
fCtAll++;
}
void toLinearArray(TArrayD& all)
{
all.Set(5*5 + 5*5*5 + 5);
for(Int_t i = 0; i < 5; i ++) {
for(Int_t j = 0; j < 5; j ++){
all[i*5+j]=Tij[i][j];
}
}
for(Int_t i = 0; i < 5; i ++) {
for(Int_t j = 0; j < 5; j ++){
for(Int_t k = 0; k < 5; k ++){
all[25+i*25+j*5+k]=Tijk[i][j][k];
}
}
}
all[150+0] = fId;
all[150+1] = fDistance;
all[150+2] = fxCut;
all[150+3] = fyCut;
all[150+4] = fCutType;
}
void fromLinearArray(TArrayD& all)
{
for(Int_t i = 0; i < 5; i ++) {
for(Int_t j = 0; j < 5; j ++){
Tij[i][j]=all[i*5+j];
}
}
for(Int_t i = 0; i < 5; i ++) {
for(Int_t j = 0; j < 5; j ++){
for(Int_t k = 0; k < 5; k ++){
Tijk[i][j][k]=all[25+i*25+j*5+k];
}
}
}
fId = all[150+0];
fDistance = all[150+1];
fxCut = all[150+2];
fyCut = all[150+3];
fCutType = all[150+4];
}
#ifndef isPluto
ClassDef(HBeamElement,1)
#endif
};
class HBeamParticle : public TObject {
public:
TVector3 fP;
TVector3 fPos;
TVector3 fOffset;
TVector3 fMomRes;
Double_t fBeamMom;
Double_t fBeamMomSmeared;
Int_t fPid;
Int_t fDetnum;
TString fName;
Double_t fbeamtube_size_x;
Double_t fbeamtube_size_y;
Bool_t fAccepted;
HBeamParticle(){
clear();
}
void clear (){
fP .SetXYZ(0.,0.,0.);
fPos .SetXYZ(0.,0.,0.);
fOffset.SetXYZ(0.,0.,0.);
fMomRes.SetXYZ(0.,0.,0.);
fBeamMom = -1.;
fBeamMomSmeared = -1.;
fPid = -10;
fDetnum = -1;
fbeamtube_size_x = -1.;
fbeamtube_size_y = -1.;
fAccepted = kTRUE;
}
void print(Bool_t printAll = kFALSE){
cout<<"---------------------------------"<<endl;
cout<<setw(12)<<fName.Data()<<" acc : "<<fAccepted<<" , ID "<<fPid<<" , Beam Mom : "<<setw(12)<<fBeamMom<<endl;
cout<<"Beam tube [x,y] : "<<setw(12)<<fbeamtube_size_x <<" , "<<setw(12)<<fbeamtube_size_y <<endl;
cout<<"P smear [x,y,z] : "<<setw(12)<<fMomRes.X()<<" , "<<setw(12)<<fMomRes .Y()<<" , "<<setw(12)<<fMomRes.Z()<<endl;
cout<<"Position [x,y,z] : "<<setw(12)<<fPos .X()<<" , "<<setw(12)<<fPos .Y()<<" , "<<setw(12)<<fPos .Z()<<endl;
cout<<"Offset [x,y,z] : "<<setw(12)<<fOffset.X()<<" , "<<setw(12)<<fOffset .Y()<<" , "<<setw(12)<<fOffset.Z()<<endl;
if(printAll){
cout<<"P [x,y,z,tot] : "<<setw(12)<<fP .X()<<" , "<<setw(12)<<fP .Y()<<" , "<<setw(12)<<fP .Z()<<" , "<<setw(12)<<fP .Mag()<<endl;
cout<<"Detector ID : "<<setw(12)<<fDetnum <<endl;
}
}
#ifndef isPluto
ClassDef(HBeamParticle,1)
#endif
};
class HBeam : public TObject {
private:
static Double_t profile(Double_t *x, Double_t *par)
{
Double_t xx = x[0];
Double_t c = 1;
Double_t mean = 0;
Double_t sigma = par[0];
Double_t flat = par[1];
Double_t result = 0;
if(xx < mean - flat) {
result = c * TMath::Gaus(xx,mean - flat,sigma);
} else if(xx > mean + flat) {
result = c * TMath::Gaus(xx,mean + flat,sigma);
} else {
result = c;
}
return result;
}
HBeamParticle fBeam;
TF1* fProfile;
vector <HBeamElement> fdetectors;
vector <HBeamElement> felements;
vector <HBeamParticle> fhistory;
Int_t fnum_target;
Double_t ftoPluto [5];
Double_t ffromPluto[5];
Bool_t setTargetElement(UInt_t n)
{
if (n < 1 || n >= felements.size()){
cout<<"HBeam::setTargetElement() : specifified target number outside range!"<<endl;
return kFALSE;
}
fnum_target = n;
Double_t shift = felements[fnum_target].fDistance;
for (UInt_t i = 0; i < felements.size(); i ++){
felements[i].fDistance -= shift;
}
return kTRUE;
}
public:
HBeam()
{
fnum_target = -1;
fProfile = new TF1("fprofile",profile,-20,20,2);
fProfile->SetParNames("sigma","flatradius");
setBeamProfile(0.05,0);
setBeamResolution(0.01,0.05,0.06);
ftoPluto[0] = 10.;
ftoPluto[1] = 0.001;
ftoPluto[2] = 10.;
ftoPluto[3] = 0.001;
ftoPluto[4] = 0.01;
for(Int_t i = 0; i < 5; i ++) ffromPluto[i] = 1./ftoPluto[i];
}
~HBeam()
{
if(fProfile) delete fProfile;
}
vector<HBeamElement>& getDetectors() { return fdetectors ; }
vector<HBeamElement>& getElements() { return felements ; }
vector<HBeamParticle>& getHistory() { return fhistory ; }
void setTargetElementOnly(Int_t id) { fnum_target=id; }
Int_t addDetector(TString name, Double_t distance,Int_t cutType,Double_t xcut=50,Double_t ycut=50)
{
HBeamElement det(name,distance,fdetectors.size()+1);
det.fxCut = TMath::Abs(xcut);
det.fyCut = TMath::Abs(ycut);
det.fCutType = cutType;
fdetectors.push_back(det);
return fdetectors.size();
}
void setBeam(Int_t id,
Double_t p,
Double_t dbeamtube_size_x,Double_t dbeamtube_size_y,
Double_t xoff = 0 ,Double_t yoff = 0)
{
fBeam.fBeamMom = TMath::Abs(p);
fBeam.fPid = id;
fBeam.fOffset.SetXYZ(xoff,yoff,0.);
fBeam.fbeamtube_size_x = TMath::Abs(dbeamtube_size_x);
fBeam.fbeamtube_size_y = TMath::Abs(dbeamtube_size_y);
}
void setBeamResolution(Double_t dpx = 0.001,Double_t dpy = 0.005,Double_t dpz = 0.06)
{
fBeam.fMomRes.SetXYZ(TMath::Abs(dpx),TMath::Abs(dpy),TMath::Abs(dpz));
}
void setBeamProfile(Double_t sigma_beam = 0.05,Double_t flat_radius = 0)
{
fProfile->SetParameter(0,TMath::Abs(sigma_beam));
fProfile->SetParameter(1,TMath::Abs(flat_radius));
}
void createBeam(HBeamParticle& part)
{
Double_t x = 0;
if ( fProfile->GetParameter(0) != 0) x = fProfile->GetRandom();
else if ( fProfile->GetParameter(0) == 0 && fProfile->GetParameter(1)!=0) x = 2 * (gRandom->Rndm() - 0.5) * fProfile->GetParameter(3);
else x = 0;
Double_t phi = gRandom->Rndm()*360.;
TVector3 p1(x,0.,felements[fnum_target].fDistance);
p1.RotateZ(phi*TMath::DegToRad());
p1 += fBeam.fOffset;
part.fPos += p1;
Double_t p = fBeam.fBeamMom + fBeam.fBeamMom * (gRandom->Rndm() - 0.5) * 2*fBeam.fMomRes.Z();
Double_t px = p * (gRandom->Rndm() - 0.5) * 2*fBeam.fMomRes.X();
Double_t py = p * (gRandom->Rndm() - 0.5) * 2*fBeam.fMomRes.Y();
Double_t pz = TMath::Sqrt(p*p - px*px - py*py);
part.fP.SetXYZ(px,py,pz);
part.fBeamMomSmeared = p;
part.fName = "beam";
part.fDetnum = -1;
}
Bool_t transport(HBeamParticle& part)
{
Double_t state [5] = { 0, 0, 0, 0, 0};
Double_t stateold[5] = {
part.fPos.X() *ffromPluto[0],
TMath::ATan2(part.fP.X(),part.fP.Z())*ffromPluto[1],
part.fPos.Y() *ffromPluto[2],
TMath::ATan2(part.fP.Y(),part.fP.Z())*ffromPluto[3],
((part.fBeamMomSmeared-fBeam.fBeamMom)/fBeam.fBeamMom)*ffromPluto[4]
};
for(UInt_t el = 0; el < felements.size(); el++){
for(Int_t i = 0; i < 5; i ++){
for(Int_t j = 0; j < 5; j ++){
state[i] += felements[el].Tij[i][j] * stateold[j];
}
for(Int_t j = 0; j < 5; j ++){
for(Int_t k = j; k < 5; k ++){
state[i] += felements[el].Tijk[i][j][k] * stateold[j] * stateold[k];
}
}
}
for(Int_t i = 0; i < 5; i ++) {
felements[el].fout[i] = state[i] * ftoPluto[i];
state[i] = 0.;
}
felements[el].fout[4] = ((part.fBeamMomSmeared-fBeam.fBeamMom)/fBeam.fBeamMom) ;
felements[el].check();
}
return kTRUE;
}
Bool_t createDetectorHits(HBeamParticle& part)
{
Double_t state [5] = { 0, 0, 0, 0, 0};
Double_t p,px,py,pz;
Bool_t accepted = kTRUE;
Bool_t acceptedDet = kTRUE;
for (UInt_t i = 0; i < fdetectors.size(); i ++) {
accepted = kTRUE;
for (UInt_t k = 0; k < felements.size() - 1; k ++) {
if(!felements[k].fAccepted) {
accepted = kFALSE;
}
if (felements[k].fDistance <= fdetectors[i].fDistance &&
fdetectors[i].fDistance < felements[k+1].fDistance) {
Double_t frac = (fdetectors[i].fDistance - felements[k].fDistance) / (felements[k+1].fDistance - felements[k].fDistance);
for(Int_t j = 0; j < 5; j ++){
state[j] = felements[k].fout[j] + frac*(felements[k+1].fout[j] - felements[k].fout[j]);
}
p = fBeam.fBeamMom * (1. + state[4]);
pz = p / sqrt(1.+ tan(state[1])*tan(state[1]) + tan(state[3])*tan(state[3]));
px = pz * tan(state[1]);
py = pz * tan(state[3]);
part.fP .SetXYZ(px,py,pz);
part.fPos.SetXYZ(state[0],state[2],fdetectors[i].fDistance);
part.fDetnum = fdetectors[i].fId;
part.fName = fdetectors[i].fName;
part.fAccepted = accepted;
fdetectors[i].fout[0] = state[0] ;
fdetectors[i].fout[2] = state[2] ;
fdetectors[i].check();
if(!fdetectors[i].fAccepted) {
part.fAccepted = kFALSE;
acceptedDet = kFALSE;
}
fhistory.push_back(part);
}
}
}
if(!felements[felements.size()-1].fAccepted) accepted = kFALSE;
return accepted&acceptedDet;
}
vector <HBeamParticle>& newParticle()
{
HBeamParticle part(fBeam);
fhistory.clear();
createBeam(part);
fhistory.push_back(part);
transport(part);
Bool_t accepted = createDetectorHits(part);
Double_t* out = &felements[fnum_target].fout[0];
Double_t p,px,py,pz;
p = fBeam.fBeamMom * (1. + out[4]);
pz = p / sqrt(1.+ tan(out[1])*tan(out[1]) + tan(out[3])*tan(out[3]));
px = pz * tan(out[1]);
py = pz * tan(out[3]);
part.fP .SetXYZ(px,py,pz);
part.fPos.SetXYZ(out[0],out[2],felements[fnum_target].fDistance);
part.fDetnum = -1;
part.fName = felements[fnum_target].fName;
part.fAccepted = accepted;
fhistory.push_back(part);
return fhistory;
}
void printBeamLine(Bool_t trans=kFALSE)
{
cout<<"############################################################################"<<endl;
cout<<"BEAMLINE ELEMENTS :"<<endl;
for(UInt_t i = 0; i < felements.size(); i ++){
felements[i].print(trans);
}
cout<<"############################################################################"<<endl;
}
void printBeamProfile()
{
cout<<"############################################################################"<<endl;
cout<<"BEAM PROFILE :"<<endl;
for(Int_t i = 0 ; i < fProfile->GetNpar();i ++){
cout<<setw(20)<<fProfile->GetParName(i)<<" : "<<setw(12)<<fProfile->GetParameter(i)<<endl;
}
fBeam.print(kFALSE);
cout<<"############################################################################"<<endl;
}
void printDetectors()
{
cout<<"############################################################################"<<endl;
cout<<"DETECTORS :"<<endl;
for(UInt_t i = 0; i < fdetectors.size(); i ++){
fdetectors[i].print(kFALSE);
}
cout<<"############################################################################"<<endl;
}
Bool_t initBeamLine(TString filename,Int_t targetElementNum,Bool_t debug=kFALSE)
{
cout<<"HBeam:: reading input!"<<endl;
Int_t nelem = 0;
std::ifstream input;
input.open(filename.Data());
if(input.fail()){
cout<<"HBeam:: could not open input!"<<endl;
return kFALSE;
}
Char_t str[1000];
Int_t nread = 1000;
Bool_t readfile = kTRUE;
Double_t aa;
Int_t ind1;
Int_t ind23;
Double_t distance;
while (readfile && !input.fail()) {
input>>distance;
if(input.peek()!='\n') input.ignore(nread,'\n');
if(input.fail() && nelem > 0 ) continue;
if(input.fail() ){ cout<<"HBeam:: "<<nelem<<" failed reading distance"<<endl; return kFALSE;}
distance *= 1000;
if(debug) cout<<nelem<<" ------------------------"<<distance<<endl;
for(Int_t i = 0; i < 5; i++) {
input.ignore(nread,'\n');
}
if(input.fail() ) {
cout<<"HBeam:: "<<nelem<<" failed after first block "<<endl;
return kFALSE;
}
input.getline(str,nread,'\n');
if(debug) cout<<"HBeam:: "<<"1st "<<str<<endl;
HBeamElement e(Form("Element[%i]",nelem),distance,nelem);
Int_t ind = 0;
for(Int_t i = 0; i < 6; i++){
if(i == 4) {
input>>aa>>aa>>aa>>aa>>aa>>aa;
continue;
}
if(i > 4) ind = i-1;
else ind = i;
input>>e.Tij[ind][0]>>e.Tij[ind][1]>>e.Tij[ind][2]>>e.Tij[ind][3]>>aa>>e.Tij[ind][4];
}
if(debug) e.printTij();
if(input.fail() ) {
cout<<"HBeam:: "<<nelem<<" failed after first order "<<endl;
return kFALSE;
}
if(input.peek() =='\n') input.ignore(nread,'\n');
input.getline(str,nread,'\n');
if(debug) cout<<"HBeam:: "<<"2nd : "<<str<<endl;
for(Int_t i = 0; i < 5; i++){
input>>ind1>>ind23>>e.Tijk[i][0][0];
input>>ind1>>ind23>>e.Tijk[i][0][1]>>ind1>>ind23>>e.Tijk[i][1][1];
input>>ind1>>ind23>>e.Tijk[i][0][2]>>ind1>>ind23>>e.Tijk[i][1][2]>>ind1>>ind23>>e.Tijk[i][2][2];
input>>ind1>>ind23>>e.Tijk[i][0][3]>>ind1>>ind23>>e.Tijk[i][1][3]>>ind1>>ind23>>e.Tijk[i][2][3]>>ind1>>ind23>>e.Tijk[i][3][3];
input>>ind1>>ind23>>aa >>ind1>>ind23>>aa >>ind1>>ind23>>aa >>ind1>>ind23>>aa >>ind1>>ind23>>aa;
input>>ind1>>ind23>>e.Tijk[i][0][4]>>ind1>>ind23>>e.Tijk[i][1][4]>>ind1>>ind23>>e.Tijk[i][2][4]>>ind1>>ind23>>e.Tijk[i][3][4]>>ind1>>ind23>>aa>>ind1>>ind23>>e.Tijk[i][4][4];
}
if(debug) e.printTijk();
if(input.fail() ) {
cout<<"HBeam:: "<<nelem<<" failed after second order "<<endl;
return kFALSE;
}
felements.push_back(e);
input.ignore(nread,'\n');
if(input.fail() ) return kFALSE;
if (!input.eof())
nelem++;
else
readfile = kFALSE;
}
input.close();
cout<<"HBeam:: finished reading input!"<<endl;
return setTargetElement(targetElementNum);
}
#ifndef isPluto
ClassDef(HBeam,1)
#endif
};
#endif