18#include "BDSBunchUserFile.hh"
20#include "BDSException.hh"
21#include "BDSGlobalConstants.hh"
22#include "BDSIonDefinition.hh"
23#include "BDSParticleDefinition.hh"
24#include "BDSUtilities.hh"
25#include "BDSWarning.hh"
27#include "parser/beam.h"
29#include "G4IonTable.hh"
30#include "G4ParticleDefinition.hh"
31#include "G4ParticleTable.hh"
35#include "src-external/gzstream/gzstream.h"
54 printedOutFirstTime(false),
55 anEnergyCoordinateInUse(false),
56 changingParticleType(false),
57 endOfFileReached(false),
58 matchDistrFileLength(false)
61 comment = std::regex(
"^\\s*\\#|\\!.*");
68 if (distrFile.empty())
69 {
throw BDSException(
"BDSBunchUserFile::CheckParameters",
"No input file specified for userfile distribution");}
81 endOfFileReached =
false;
82 if (!printedOutFirstTime)
84 G4cout <<
"BDSBunchUserFile::OpenBunchFile> opening " << distrFilePath << G4endl;
85 printedOutFirstTime =
true;
88 InputBunchFile.open(distrFilePath);
89 if (!InputBunchFile.good())
90 {
throw BDSException(
"BDSBunchUserFile::OpenBunchFile>",
"Cannot open bunch file " + distrFilePath);}
96 InputBunchFile.clear();
97 InputBunchFile.close();
98 endOfFileReached =
true;
106 std::regex colons(
":");
107 std::vector<std::string> results;
109 std::sregex_token_iterator end;
110 for (; iter != end; ++iter)
112 std::string res = (*iter).str();
113 results.push_back(res);
115 for (
auto const& token : results)
119 if(token.substr(0,1)==
"E" || token.substr(0,1)==
"P")
122 if (token.substr(0,2)==
"Ek")
124 vari = token.substr(0,2);
125 rest = token.substr(2);
129 vari = token.substr(0,1);
130 rest = token.substr(1);
134 else if (token.substr(0,1)==
"t")
136 vari = token.substr(0, 1);
137 rest = token.substr(1);
140 else if ( ( token.substr(0,1)==
"x" && token.substr(1,1)!=
"p" ) ||
141 ( token.substr(0,1)==
"y" && token.substr(1,1)!=
"p" ) ||
142 ( token.substr(0,1)==
"z" && token.substr(1,1)!=
"p" ) )
144 vari = token.substr(0,1);
145 rest = token.substr(1);
148 else if ( (token.substr(0,2)==
"xp") ||
149 (token.substr(0,2)==
"yp") ||
150 (token.substr(0,2)==
"zp") )
152 vari = token.substr(0,2);
153 rest = token.substr(2);
156 else if (token.substr(0, 1) ==
"S")
158 vari = token.substr(0, 1);
159 rest = token.substr(1);
163 else if(token.substr(0,5)==
"pdgid")
170 else if(token.substr(0,1)==
"w")
176 else if (token.substr(0,1)==
"-")
185 G4String message =
"Cannot determine bunch data format. Failed at token: " + token;
190 std::set<G4String> energyKeys = {
"E",
"Ek",
"P"};
193 std::set<G4String> zKeys = {
"z",
"S"};
200 auto inSet = [=](
const G4String& v){
return s.find(v) != s.end();};
202 int count = std::count_if(
fields.begin(),
fields.end(), inSetD);
205 G4String message =
"More than one of the following set in user file columns (\"distrFileFormat\") ";
206 for (
const auto& st : s)
211 message +=
"\nPossibly conflicting information. Ensure only one by skipping others with \"-\" symbol";
212 throw BDSException(
"BDSBunchUserFile::CheckConflictingParameters>", message);
219 const G4String& rest,
231 G4int pos1 = (G4int)rest.find(
"[");
232 G4int pos2 = (G4int)rest.find(
"]");
233 if (pos1 < 0 || pos2 < 0)
235 G4String message =
"Missing bracket [] in units of \"distrFileFormat\"\n";
236 message +=
"variable : \"" + uName +
"\" and unit \"" + rest +
"\"";
237 throw BDSException(
"BDSBunchUserFile::CheckAndParseUnits>", message);
241 G4String fmt = rest.substr(pos1 + 1, pos2 - 1);
243 sd.unit = unitParser(fmt);
252 for (G4int i = 0; i < nValues; i++)
262 {G4cout <<
"BDSBunchUserFile> ignoring " <<
nlinesIgnore <<
" lines" << G4endl;}
271 G4String msg =
"end of file reached after line " + std::to_string(
lineCounter);
272 msg +=
" before nlinesIgnore ("+std::to_string(
nlinesIgnore)+
") was reached.";
273 throw BDSException(
"BDSBunchUserFile::SkipNLinesIgnoreIntoFile>", msg);
285 {G4cout <<
"BDSBunchUserFile> skipping " <<
nlinesSkip <<
" valid lines" << G4endl;}
291 G4int nLinesValidRead = 0;
299 IncrementNEventsInFileSkipped((
unsigned long long int)
nlinesSkip);
307 G4Transform3D beamlineTransformIn,
308 const G4double beamlineSIn)
324 return std::all_of(line.begin(), line.end(), isspace) || std::regex_search(line, comment);
334 G4long nLinesValid = 0;
352 G4String msg =
"nlinesSkip is greater than the number of valid lines (" + std::to_string(nLinesValidData);
354 throw BDSException(
"BDSBunchUserFile::Initialise>", msg);
358 G4bool nGenerateHasBeenSet = g->NGenerateSet();
359 G4int nEventsPerLoop = (G4int)(nLinesValidData -
nlinesSkip);
361 G4int nAvailable = nEventsPerLoop * distrFileLoopNTimes;
362 G4int nGenerate = g->NGenerate();
363 if (matchDistrFileLength)
365 if (!nGenerateHasBeenSet)
367 g->SetNumberToGenerate(nAvailable);
368 G4cout <<
"BDSBunchUserFile::Initialise> distrFileMatchLength is true -> simulating " << nEventsPerLoop <<
" events";
369 if (distrFileLoopNTimes > 1)
370 {G4cout <<
" " << distrFileLoopNTimes <<
" times";}
375 G4int nEventsRemaining = nAvailable - g->StartFromEvent();
376 g->SetNumberToGenerate(nEventsRemaining);
377 G4cout <<
"BDSBunchUserFile::Initialise> distrFileMatchLength + recreation -> simulate the "
378 << nEventsRemaining <<
" lines left given startFromEvent including possible looping" << G4endl;
383 G4cout <<
"BDSBunchUserFile::Initialise> matchDistrFileLength has been requested "
384 <<
"but ngenerate has been specified -> use ngenerate" << G4endl;
386 if (nGenerate > nAvailable)
388 G4String msg =
"ngenerate (" + std::to_string(nGenerate) +
") is greater than the number of valid lines (";
389 msg += std::to_string(nLinesValidData) +
") and distrFileMatchLength is on.\nChange ngenerate to <= # lines";
390 msg +=
", or don't specifcy ngenerate.\n";
391 msg +=
"This includes nlinesSkip.";
392 throw BDSException(
"BDSBunchUserFile::Initialise>", msg);
398 if ((nGenerate > nEventsPerLoop) && !distrFileLoop)
400 G4String msg =
"ngenerate (" + std::to_string(nGenerate) +
") is greater than the number of valid lines (";
401 msg += std::to_string(nLinesValidData) +
") but distrFileLoop is false in the beam command";
402 throw BDSException(
"BDSBunchUserFile::Initialise>", msg);
415 G4cout <<
"BDSBunchUserFile> End of file reached." << G4endl;
419 G4cout <<
"BDSBunchUserFile> Returning to beginning of file (including nlinesIgnore & nlinesSkip) for next event." << G4endl;
425 {
throw BDSException(__METHOD_NAME__,
"distrFileLoop off but requesting another set of coordinates.");}
432 G4cout <<
"BDSBunchUserFile::RecreateAdvanceToEvent> Advancing file to event: " << eventOffset << G4endl;
433 G4int nEventsPerLoop = nLinesValidData -
nlinesSkip;
434 G4int nAvailable = nEventsPerLoop * distrFileLoopNTimes;
435 G4int nEventsRemaining = nAvailable - eventOffset;
436 if (eventOffset > nEventsPerLoop)
442 G4int nToRoll = eventOffset % nEventsPerLoop;
443 eventOffset = nToRoll;
447 G4String msg =
"eventOffset (" + std::to_string(eventOffset) +
") is greater than the number of valid data lines in this file.\n";
448 msg +=
"This includes nlinesSkip.";
449 throw BDSException(
"BDSBunchUserFile::RecreateAdvanceToEvent>", msg);
454 if (nGenerate > nEventsRemaining && !distrFileLoop)
456 G4String msg =
"ngenerate (" + std::to_string(nGenerate) +
") requested in recreate mode is greater than number\n";
457 msg +=
"of remaining valid lines in file (" + std::to_string(nEventsRemaining) +
") and distrFileLoop is turned off.";
467 for (G4int i = 0; i < eventOffset; i++)
489 G4double E = 0, Ek = 0, P = 0, x = 0, y = 0, z = 0, xp = 0, yp = 0, zp = 0, t = 0;
493 G4bool zpdef =
false;
497 G4bool updateParticleDefinition =
false;
505 G4bool lineIsBad =
true;
526 std::vector<std::string> results;
527 std::regex wspace(
"\\s+");
529 std::sregex_token_iterator iter(line.begin(), line.end(), wspace, -1);
530 std::sregex_token_iterator end;
531 for (; iter != end; ++iter)
533 std::string res = (*iter).str();
534 results.push_back(res);
537 if (results.size() <
fields.size())
539 std::string message =
"Invalid line at line " + std::to_string(
lineCounter) +
540 ". Expected " + std::to_string(
fields.size()) +
541 " columns , but got " + std::to_string(results.size()) +
546 std::stringstream ss(line);
551 else if(it->name==
"Ek")
552 {
ReadValue(ss, Ek); Ek *= (CLHEP::GeV * it->unit);}
553 else if(it->name==
"E")
554 {
ReadValue(ss, E); E *= (CLHEP::GeV * it->unit);}
555 else if(it->name==
"P")
556 {
ReadValue(ss, P); P *= (CLHEP::GeV * it->unit);}
557 else if(it->name==
"t")
558 {
ReadValue(ss, t); t *= (CLHEP::s * it->unit); tdef =
true;}
559 else if(it->name==
"x")
560 {
ReadValue(ss, x); x *= (CLHEP::m * it->unit);}
561 else if(it->name==
"y")
562 {
ReadValue(ss, y); y *= (CLHEP::m * it->unit);}
563 else if(it->name==
"z")
564 {
ReadValue(ss, z); z *= (CLHEP::m * it->unit);}
565 else if(it->name==
"xp") {
ReadValue(ss, xp); xp *= ( CLHEP::radian * it->unit );}
566 else if(it->name==
"yp") {
ReadValue(ss, yp); yp *= ( CLHEP::radian * it->unit );}
567 else if(it->name==
"zp") {
ReadValue(ss, zp); zp *= ( CLHEP::radian * it->unit ); zpdef =
true;}
568 else if(it->name==
"pdgid")
571 updateParticleDefinition =
true;
575 else if (it->name ==
"S")
578 z *= CLHEP::m * it->unit;
580 else if(it->name==
"weight")
593 {updateParticleDefinition =
true;}
610 G4ParticleTable* particleTable = G4ParticleTable::GetParticleTable();
611 G4ParticleDefinition* g4ParticleDef =
nullptr;
614 {g4ParticleDef = particleTable->FindParticle(type);}
617 G4IonTable* ionTable = particleTable->GetIonTable();
618 G4int ionA, ionZ, ionLevel;
620 G4IonTable::GetNucleusByEncoding(type, ionZ, ionA, ionE, ionLevel);
622 g4ParticleDef = ionTable->GetIon(ionDef->
Z(), ionDef->
A(), ionDef->
ExcitationEnergy());
626 {
throw BDSException(
"BDSBunchUserFile> Particle \"" + std::to_string(type) +
"\" not found");}
647template <
typename Type>
666 else if (fmt ==
"GeV")
668 else if (fmt ==
"MeV")
670 else if (fmt ==
"KeV")
672 else if (fmt ==
"eV")
675 {
throw BDSException(__METHOD_NAME__,
"Unrecognised energy unit! " +fmt);}
684 else if (fmt ==
"cm")
686 else if (fmt ==
"mm")
688 else if (fmt ==
"mum" || fmt ==
"um")
690 else if (fmt ==
"nm")
693 {
throw BDSException(__METHOD_NAME__,
"Unrecognised length unit! " + fmt);}
702 else if (fmt ==
"mrad")
704 else if (fmt ==
"murad" || fmt ==
"urad")
706 else if (fmt ==
"nrad")
709 {
throw BDSException(__METHOD_NAME__,
"Unrecognised angle unit! " + fmt);}
718 else if (fmt ==
"ms")
720 else if (fmt ==
"mus" || fmt ==
"us")
722 else if (fmt ==
"ns")
724 else if (fmt ==
"mm/c")
725 {
unit = (CLHEP::mm/CLHEP::c_light)/CLHEP::s;}
726 else if (fmt ==
"nm/c")
727 {
unit = (CLHEP::nm/CLHEP::c_light)/CLHEP::s;}
729 {
throw BDSException(__METHOD_NAME__,
"Unrecognised time unit! " + fmt);}
An intermediate layer for any bunch classes that are file based.
unsigned long long int nEventsInFile
The number of entries in the file loaded.
virtual void SetOptions(const BDSParticleDefinition *beamParticle, const GMAD::Beam &beam, const BDSBunchType &distrType, G4Transform3D beamlineTransformIn=G4Transform3D::Identity, const G4double beamlineS=0)
Pull out the relevant options and then pass through to BDSBunch::SetOptions().
A bunch distribution that reads a user specified column file.
void CheckConflictingParameters(const std::set< G4String > &s) const
Check conflicting columns aren't specified in file, e.g. P and Ek. Throw exception if wrong.
virtual void RecreateAdvanceToEvent(G4int eventOffset)
G4double ffact
Cache of flip factor from global constants.
void ReadValue(std::stringstream &stream, Type &value)
G4int lineCounter
Line counter.
G4long CountNLinesValidDataInFile()
void SkipNLinesSkip(G4bool usualPrintOut=true)
T InputBunchFile
The file handler. Templated as could be std::ifstream or igzstream for example.
G4bool SkippableLine(const std::string &line) const
Return true if a line is all whitespace or is commented out (starts with '#').
virtual BDSParticleCoordsFullGlobal GetNextParticleValid(G4int maxTries)
G4bool changingParticleType
Whether the particle type is a column.
void skip(std::stringstream &stream, G4int nvalues)
void SkipNLinesIgnoreIntoFile(G4bool usualPrintOut=true)
void ParseFileFormat()
Parse the column tokens and units factors.
G4long nlinesIgnore
Number of lines that will be ignored at the start the file.
virtual void SetOptions(const BDSParticleDefinition *beamParticle, const GMAD::Beam &beam, const BDSBunchType &distrType, G4Transform3D beamlineTransformIn=G4Transform3D::Identity, const G4double beamlineS=0)
Pull out the relevant options and then pass through to BDSBunch::SetOptions().
G4String distrFilePath
Bunch file including absolute path.
G4String bunchFormat
Format of the file.
G4long nlinesSkip
Number of lines that will be skipped after the nlinesIgnore.
G4double particleMass
Cache of nominal beam particle mass.
std::list< Doublet > fields
List of variables to parse on each line.
void CloseBunchFile()
Close the file handler.
virtual void CheckParameters()
virtual BDSParticleCoordsFull GetNextParticleLocal()
Get the next particle.
virtual void Initialise()
Open the file and skip lines.
G4String distrFile
Bunch file.
void OpenBunchFile()
Open the file and check it's open.
G4bool anEnergyCoordinateInUse
Whether Et, Ek or P are in the columns.
G4double Yp0
Centre of distributions.
virtual void RecreateAdvanceToEvent(G4int eventOffset)
G4bool particleDefinitionHasBeenUpdated
G4bool useCurvilinear
Whether to ignore z and use s and transform for curvilinear coordinates.
G4double Z0
Centre of distributions.
G4double X0
Centre of distributions.
G4double Xp0
Centre of distributions.
G4double E0
Centre of distributions.
G4double Y0
Centre of distributions.
BDSParticleCoordsFullGlobal GetNextParticle()
static G4double CalculateZp(G4double xp, G4double yp, G4double Zp0)
Calculate zp safely based on other components.
BDSParticleDefinition * particleDefinition
Particle definition for bunch - this class owns it.
virtual void CheckParameters()
General exception with possible name of object and message.
static BDSGlobalConstants * Instance()
Access method.
Class to parse an ion particle definition.
G4double ExcitationEnergy() const
Accessor.
A set of particle coordinates in both local and global.
A set of particle coordinates including energy and weight.
Wrapper for particle definition.
G4double Mass() const
Accessor.
void SetEnergies(G4double totalEnergyIn, G4double kineticEnergyIn, G4double momentumIn)
G4double TotalEnergy() const
Accessor.
Improve type-safety of native enum data type in C++.
std::string distrFileFormat
beam parameters
std::string distrFile
beam parameters
int nlinesIgnore
Ignore first lines in the input bunch file.
int nlinesSkip
Number of event lines to skip after the ignore lines.
bool distrFileMatchLength
beam parameters
Return either G4Tubs or G4CutTubs depending on flat face.
G4String GetFullPath(G4String filename, bool excludeNameFromPath=false, bool useCWDForPrefix=false)
G4double ParseTimeUnit(const G4String &fmt)
G4double ParseEnergyUnit(const G4String &fmt)
G4double ParseAngleUnit(const G4String &fmt)
G4bool IsFinite(G4double value, G4double tolerance=std::numeric_limits< double >::epsilon())
G4double ParseLengthUnit(const G4String &fmt)
Struct for name and unit pair.
G4double unit
relative to SI units, i.e. mm=0.001 etc.