BDSIM
BDSIM is a Geant4 extension toolkit for simulation of particle transport in accelerator beamlines.
Loading...
Searching...
No Matches
BDSBOptrChangeCrossSection.cc
1/*
2Beam Delivery Simulation (BDSIM) Copyright (C) Royal Holloway,
3University of London 2001 - 2023.
4
5This file is part of BDSIM.
6
7BDSIM is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published
9by the Free Software Foundation version 3 of the License.
10
11BDSIM is distributed in the hope that it will be useful, but
12WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with BDSIM. If not, see <http://www.gnu.org/licenses/>.
18*/
19// this class needs headers from Geant4 10.1 onwards
20#include "G4Version.hh"
21
22#if G4VERSION_NUMBER > 1009
23
24#include "BDSBOptrChangeCrossSection.hh"
25#include "BDSDebug.hh"
26#include "BDSException.hh"
27#include "BDSPhysicsUtilities.hh"
28
29#include "globals.hh"
30#include "G4BiasingProcessInterface.hh"
31#include "G4BiasingProcessSharedData.hh"
32#include "G4BOptnChangeCrossSection.hh"
33#include "G4InteractionLawPhysical.hh"
34#include "G4IonTable.hh"
35#include "G4ParticleDefinition.hh"
36#include "G4ParticleTable.hh"
37#include "G4Proton.hh"
38#include "G4VProcess.hh"
39
40#include <limits>
41#include <regex>
42
43BDSBOptrChangeCrossSection::BDSBOptrChangeCrossSection(const G4String& particleNameIn,
44 const G4String& name):
45 G4VBiasingOperator(name),
46 fSetup(true),
47 particleName(particleNameIn),
48 particleIsIon(false)
49{
50 fParticleToBias = G4ParticleTable::GetParticleTable()->FindParticle(particleName);
51
52 if (!fParticleToBias)
53 {throw BDSException(__METHOD_NAME__, "Particle \"" + particleName + "\" not found");}
54
55 particleIsIon = BDS::IsIon(fParticleToBias);
56}
57
58BDSBOptrChangeCrossSection::~BDSBOptrChangeCrossSection()
59{
60 for (auto change : fChangeCrossSectionOperations)
61 {delete change.second;}
62}
63
64void BDSBOptrChangeCrossSection::StartRun()
65{
66 // Setup stage:
67 // Start by collecting processes under biasing, create needed biasing
68 // operations and associate these operations to the processes:
69 if (fSetup)
70 {
71 const G4ProcessManager* processManager = fParticleToBias->GetProcessManager();
72 const G4BiasingProcessSharedData* sharedData = G4BiasingProcessInterface::GetSharedData(processManager);
73
74 if (sharedData)
75 {
76 // sharedData tested, as is can happen a user attaches an operator to a
77 // volume but without defined BiasingProcessInterface processes.
78 for (const auto& wrapperProcess : sharedData->GetPhysicsBiasingProcessInterfaces())
79 {
80 G4String operationName = "XSchange-"+wrapperProcess->GetWrappedProcess()->GetProcessName();
81 fChangeCrossSectionOperations[wrapperProcess] = new G4BOptnChangeCrossSection(operationName);
82 fXSScale[wrapperProcess] = 1.0;
83 fPrimaryScale[wrapperProcess] = 0;
84 }
85 }
86 fSetup = false;
87 }
88}
89
90void BDSBOptrChangeCrossSection::SetBias(const G4String& processName,
91 G4double bias,
92 G4int iPrimary)
93{
94 const G4ProcessManager* processManager = fParticleToBias->GetProcessManager();
95 const G4BiasingProcessSharedData* sharedData = G4BiasingProcessInterface::GetSharedData(processManager);
96
97 G4bool allProcesses = false;
98 if (processName == "all")
99 {allProcesses = true;}
100
101 G4bool processFound = false;
102 for (const auto& wrapperProcess : sharedData->GetPhysicsBiasingProcessInterfaces())
103 {
104 G4String currentProcess = wrapperProcess->GetWrappedProcess()->GetProcessName();
105
106 // check if the name is already wrapped for biasing of some kind or splitting
107 std::regex braces("[\\w\\-\\+_$]*\\((\\w+)\\)");
108 //std::regex braces("[\\w\\-\\_\\+]*\\‍((\\w+)\\‍)");
109 std::smatch match;
110 if (std::regex_search(currentProcess, match, braces))
111 {currentProcess = match[1];} // overwrite the variable to match (in this scope)
112
113 if (allProcesses || processName == currentProcess)
114 {
115 fXSScale[wrapperProcess] = bias;
116 fPrimaryScale[wrapperProcess] = iPrimary;
117 processFound = true; // the process was found at some point
118 }
119 }
120 if (!processFound)
121 {
122 G4cout << "\nCouldn't find process by name. Available processes are:" << G4endl;
123 for (const auto wrapperProcess : sharedData->GetPhysicsBiasingProcessInterfaces())
124 {
125 G4String currentProcessName = wrapperProcess->GetWrappedProcess()->GetProcessName();
126 G4cout << "\"" << currentProcessName << "\"" << G4endl;
127 }
128 throw BDSException(__METHOD_NAME__, "Process \"" + processName +
129 "\" not found registered to particle \"" + particleName + "\"");
130 }
131}
132
133G4VBiasingOperation* BDSBOptrChangeCrossSection::ProposeOccurenceBiasingOperation(const G4Track* track,
134 const G4BiasingProcessInterface* callingProcess)
135{
136 // Check if current particle type is the one to bias:
137 const G4ParticleDefinition* definition = track->GetDefinition();
138 if (particleIsIon)
139 {// we're looking for an ion and this generally isn't an ion
140 if (!G4IonTable::IsIon(definition) || definition == G4Proton::Definition())
141 {return nullptr;}
142 // else it's generally an ion so continue - ie apply GenericIon to any ion
143 }
144 else if (definition != fParticleToBias)
145 {return nullptr;}
146
147 // select and setup the biasing operation for current callingProcess:
148 // Check if the analog cross-section well defined : for example, the conversion
149 // process for a gamma below e+e- creation threshold has an DBL_MAX interaction
150 // length. Nothing is done in this case (ie, let analog process to deal with the case)
151
152 G4double analogInteractionLength = callingProcess->GetWrappedProcess()->GetCurrentInteractionLength();
153 if (analogInteractionLength > std::numeric_limits<double>::max()/10.)
154 {return nullptr;}
155
156 // protect against negative interaction lengths
157 // sometimes this appears as -1 - exactly -1
158 if (analogInteractionLength < 0)
159 {return nullptr;}
160
161 // Analog cross-section is well-defined:
162 G4double analogXS = 1./analogInteractionLength;
163
164 // Choose a constant cross-section bias. But at this level, this factor can be made
165 // direction dependent, like in the exponential transform MCNP case, or it
166 // can be chosen differently, depending on the process, etc.
167 G4double XStransformation = 1.0;
168
169 // fetch the operation associated to this callingProcess:
170 G4BOptnChangeCrossSection* operation = fChangeCrossSectionOperations[callingProcess];
171
172 // get the operation that was proposed to the process in the previous step:
173 G4VBiasingOperation* previousOperation = callingProcess->GetPreviousOccurenceBiasingOperation();
174
175 // check for only scaling primary
176 if ( fPrimaryScale[callingProcess] == 2 && track->GetParentID() != 0 )
177 {return nullptr;}
178 if ( fPrimaryScale[callingProcess] == 3 && track->GetParentID() == 0 )
179 {return nullptr;}
180 XStransformation = fXSScale[callingProcess];
181
182 // STB Just return the operation before the multiple sampling check
183 //operation->SetBiasedCrossSection( XStransformation * analogXS );
184 //operation->Sample();
185
186 // now setup the operation to be returned to the process: this
187 // consists in setting the biased cross-section, and in asking
188 // the operation to sample its exponential interaction law.
189 // To do this, to first order, the two lines:
190 // operation->SetBiasedCrossSection( XStransformation * analogXS );
191 // operation->Sample();
192 // are correct and sufficient.
193 // But, to avoid having to shoot a random number each time, we sample
194 // only on the first time the operation is proposed, or if the interaction
195 // occured. If the interaction did not occur for the process in the previous,
196 // we update the number of interaction length instead of resampling.
197
198 if (!previousOperation)
199 {
200 operation->SetBiasedCrossSection( XStransformation * analogXS );
201 operation->Sample();
202 }
203 else
204 {
205 if (previousOperation != operation)
206 {// should not happen !
207 //G4cout << __METHOD_NAME__ << "Logic Problem" << G4endl;
208 return nullptr;
209 }
210 if (operation->GetInteractionOccured())
211 {
212 operation->SetBiasedCrossSection( XStransformation * analogXS );
213 operation->Sample();
214 }
215 else
216 {
217 // update the 'interaction length' and underneath 'number of interaction lengths'
218 // for past step (this takes into accout the previous step cross-section value)
219 operation->UpdateForStep(callingProcess->GetPreviousStepSize());
220 // update the cross-section value:
221 operation->SetBiasedCrossSection(XStransformation * analogXS);
222 // forces recomputation of the 'interaction length' taking into account above
223 // new cross-section value [tricky : to be improved]
224 operation->UpdateForStep(0.0);
225 }
226 }
227 return operation;
228}
229
230void BDSBOptrChangeCrossSection::OperationApplied(const G4BiasingProcessInterface* callingProcess,
231 G4BiasingAppliedCase,
232 G4VBiasingOperation* occurenceOperationApplied,
233 G4double,
234 G4VBiasingOperation*,
235 const G4VParticleChange*)
236{
237 G4BOptnChangeCrossSection* operation = fChangeCrossSectionOperations[callingProcess];
238 if (operation == occurenceOperationApplied)
239 {operation->SetInteractionOccured();}
240}
241
242#endif
General exception with possible name of object and message.
Definition: BDSException.hh:35
G4bool IsIon(const G4ParticleDefinition *particle)
Whether a particle is an ion. A proton is counted NOT as an ion.