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