Geant4 Cross Reference

Cross-Referencing   Geant4
Geant4/processes/biasing/generic/src/G4BiasingProcessInterface.cc

Version: [ ReleaseNotes ] [ 1.0 ] [ 1.1 ] [ 2.0 ] [ 3.0 ] [ 3.1 ] [ 3.2 ] [ 4.0 ] [ 4.0.p1 ] [ 4.0.p2 ] [ 4.1 ] [ 4.1.p1 ] [ 5.0 ] [ 5.0.p1 ] [ 5.1 ] [ 5.1.p1 ] [ 5.2 ] [ 5.2.p1 ] [ 5.2.p2 ] [ 6.0 ] [ 6.0.p1 ] [ 6.1 ] [ 6.2 ] [ 6.2.p1 ] [ 6.2.p2 ] [ 7.0 ] [ 7.0.p1 ] [ 7.1 ] [ 7.1.p1 ] [ 8.0 ] [ 8.0.p1 ] [ 8.1 ] [ 8.1.p1 ] [ 8.1.p2 ] [ 8.2 ] [ 8.2.p1 ] [ 8.3 ] [ 8.3.p1 ] [ 8.3.p2 ] [ 9.0 ] [ 9.0.p1 ] [ 9.0.p2 ] [ 9.1 ] [ 9.1.p1 ] [ 9.1.p2 ] [ 9.1.p3 ] [ 9.2 ] [ 9.2.p1 ] [ 9.2.p2 ] [ 9.2.p3 ] [ 9.2.p4 ] [ 9.3 ] [ 9.3.p1 ] [ 9.3.p2 ] [ 9.4 ] [ 9.4.p1 ] [ 9.4.p2 ] [ 9.4.p3 ] [ 9.4.p4 ] [ 9.5 ] [ 9.5.p1 ] [ 9.5.p2 ] [ 9.6 ] [ 9.6.p1 ] [ 9.6.p2 ] [ 9.6.p3 ] [ 9.6.p4 ] [ 10.0 ] [ 10.0.p1 ] [ 10.0.p2 ] [ 10.0.p3 ] [ 10.0.p4 ] [ 10.1 ] [ 10.1.p1 ] [ 10.1.p2 ] [ 10.1.p3 ] [ 10.2 ] [ 10.2.p1 ] [ 10.2.p2 ] [ 10.2.p3 ] [ 10.3 ] [ 10.3.p1 ] [ 10.3.p2 ] [ 10.3.p3 ] [ 10.4 ] [ 10.4.p1 ] [ 10.4.p2 ] [ 10.4.p3 ] [ 10.5 ] [ 10.5.p1 ] [ 10.6 ] [ 10.6.p1 ] [ 10.6.p2 ] [ 10.6.p3 ] [ 10.7 ] [ 10.7.p1 ] [ 10.7.p2 ] [ 10.7.p3 ] [ 10.7.p4 ] [ 11.0 ] [ 11.0.p1 ] [ 11.0.p2 ] [ 11.0.p3, ] [ 11.0.p4 ] [ 11.1 ] [ 11.1.1 ] [ 11.1.2 ] [ 11.1.3 ] [ 11.2 ] [ 11.2.1 ] [ 11.2.2 ] [ 11.3.0 ]

  1 //
  2 // ********************************************************************
  3 // * License and Disclaimer                                           *
  4 // *                                                                  *
  5 // * The  Geant4 software  is  copyright of the Copyright Holders  of *
  6 // * the Geant4 Collaboration.  It is provided  under  the terms  and *
  7 // * conditions of the Geant4 Software License,  included in the file *
  8 // * LICENSE and available at  http://cern.ch/geant4/license .  These *
  9 // * include a list of copyright holders.                             *
 10 // *                                                                  *
 11 // * Neither the authors of this software system, nor their employing *
 12 // * institutes,nor the agencies providing financial support for this *
 13 // * work  make  any representation or  warranty, express or implied, *
 14 // * regarding  this  software system or assume any liability for its *
 15 // * use.  Please see the license in the file  LICENSE  and URL above *
 16 // * for the full disclaimer and the limitation of liability.         *
 17 // *                                                                  *
 18 // * This  code  implementation is the result of  the  scientific and *
 19 // * technical work of the GEANT4 collaboration.                      *
 20 // * By using,  copying,  modifying or  distributing the software (or *
 21 // * any work based  on the software)  you  agree  to acknowledge its *
 22 // * use  in  resulting  scientific  publications,  and indicate your *
 23 // * acceptance of all terms of the Geant4 Software license.          *
 24 // ********************************************************************
 25 //
 26 // G4BiasingProcessInterface
 27 // --------------------------------------------------------------------
 28 
 29 #include "G4BiasingProcessInterface.hh"
 30 #include "G4VBiasingOperator.hh"
 31 #include "G4VBiasingOperation.hh"
 32 #include "G4ParticleChangeForOccurenceBiasing.hh"
 33 #include "G4ParticleChangeForNothing.hh"
 34 #include "G4VBiasingInteractionLaw.hh"
 35 #include "G4InteractionLawPhysical.hh"
 36 #include "G4ProcessManager.hh"
 37 #include "G4BiasingAppliedCase.hh"
 38 #include "G4ParallelGeometriesLimiterProcess.hh"
 39 
 40 G4Cache<G4bool> G4BiasingProcessInterface::fResetInteractionLaws;// = true;
 41 G4Cache<G4bool> G4BiasingProcessInterface::fCommonStart;//          = true;
 42 G4Cache<G4bool> G4BiasingProcessInterface::fCommonEnd;//            = true;
 43 G4Cache<G4bool> G4BiasingProcessInterface::fDoCommonConfigure;
 44 
 45 G4BiasingProcessInterface::G4BiasingProcessInterface(const G4String& name)
 46   : G4VProcess( name ),
 47     fResetWrappedProcessInteractionLength( true )
 48 {
 49   for (G4int i = 0 ; i < 8 ; i++)  fFirstLastFlags[i] = false;
 50   fResetInteractionLaws.Put( true );
 51   fCommonStart         .Put( true );
 52   fCommonEnd           .Put( true );
 53   fDoCommonConfigure   .Put( true );
 54 }
 55 
 56 
 57 G4BiasingProcessInterface::
 58 G4BiasingProcessInterface(G4VProcess* wrappedProcess,
 59                           G4bool wrappedIsAtRest, 
 60                           G4bool wrappedIsAlongStep,
 61                           G4bool wrappedIsPostStep,
 62                           G4String useThisName)
 63   : G4VProcess(useThisName != ""
 64                  ? useThisName
 65                  : "biasWrapper("+wrappedProcess->GetProcessName()+")",
 66                wrappedProcess->GetProcessType()),
 67     fWrappedProcess( wrappedProcess ),
 68     fIsPhysicsBasedBiasing( true ),
 69     fWrappedProcessIsAtRest( wrappedIsAtRest ),
 70     fWrappedProcessIsAlong( wrappedIsAlongStep ),
 71     fWrappedProcessIsPost( wrappedIsPostStep )
 72 {
 73   for (G4int i = 0 ; i < 8 ; ++i)
 74     fFirstLastFlags[i] = false;
 75   fResetInteractionLaws.Put( true );
 76   fCommonStart.Put(true);
 77   fCommonEnd.Put(true);
 78   fDoCommonConfigure.Put(true);
 79   
 80   SetProcessSubType(fWrappedProcess->GetProcessSubType());
 81 
 82   // -- create physical interaction law:
 83   fPhysicalInteractionLaw = new G4InteractionLawPhysical("PhysicalInteractionLawFor("+GetProcessName()+")");
 84   // -- instantiate particle change wrapper for occurrence biaising:
 85   fOccurenceBiasingParticleChange = new G4ParticleChangeForOccurenceBiasing("biasingPCfor"+GetProcessName());
 86   // -- instantiate a "do nothing" particle change:
 87   fDummyParticleChange = new G4ParticleChangeForNothing();
 88 }
 89 
 90 G4BiasingProcessInterface::~G4BiasingProcessInterface()
 91 {
 92   delete fPhysicalInteractionLaw;
 93   delete fOccurenceBiasingParticleChange;
 94   delete fDummyParticleChange;
 95 }
 96 
 97 const G4BiasingProcessSharedData*
 98 G4BiasingProcessInterface::GetSharedData( const G4ProcessManager* mgr )
 99 {
100   const auto & itr = G4BiasingProcessSharedData::fSharedDataMap.Find( mgr );
101   if ( itr !=  G4BiasingProcessSharedData::fSharedDataMap.End( ) )
102   {
103     return (*itr).second;
104   }
105   else return nullptr;
106 }
107 
108 
109 void G4BiasingProcessInterface::StartTracking(G4Track* track)
110 {
111   fCurrentTrack = track;
112   if ( fIsPhysicsBasedBiasing ) fWrappedProcess->StartTracking(fCurrentTrack);
113   fOccurenceBiasingOperation          = nullptr;
114   fPreviousOccurenceBiasingOperation  = nullptr;
115   fFinalStateBiasingOperation         = nullptr;
116   fPreviousFinalStateBiasingOperation = nullptr;
117   fNonPhysicsBiasingOperation         = nullptr;
118   fPreviousNonPhysicsBiasingOperation = nullptr;
119   fBiasingInteractionLaw              = nullptr;
120   fPreviousBiasingInteractionLaw      = nullptr;
121   
122   fPreviousStepSize = -1.0;
123   
124   fResetWrappedProcessInteractionLength = false;
125   
126   if ( fCommonStart.Get() )
127   {
128     fCommonStart.Put( false );// = false;
129     fCommonEnd.Put( true  );// = true;
130       
131     fSharedData->fCurrentBiasingOperator = nullptr;
132     fSharedData->fPreviousBiasingOperator = nullptr;
133 
134     // -- Add a  "fSharedData->nStarting" here and outside bracket "fSharedData->nStarting++" and " if (fSharedData->nStarting) == fSharedData->(vector interface length)"
135     // -- call to the loop "StartTracking" of operators"
136       
137     for (std::size_t optr=0 ; optr<(G4VBiasingOperator::GetBiasingOperators()).size(); ++optr)
138     {
139       (G4VBiasingOperator::GetBiasingOperators())[optr]->StartTracking( fCurrentTrack );
140     }
141   }
142 }
143 
144 void G4BiasingProcessInterface::EndTracking()
145 {
146   if ( fIsPhysicsBasedBiasing )
147     fWrappedProcess->EndTracking();
148   if ( fSharedData->fCurrentBiasingOperator)
149     (fSharedData->fCurrentBiasingOperator)->ExitingBiasing(fCurrentTrack, this); 
150   fBiasingInteractionLaw = nullptr;
151 
152   // -- Inform operators of end of tracking:
153   if ( fCommonEnd.Get() )
154   {
155     fCommonEnd  .Put( false );// = false;
156     fCommonStart.Put( true );// = true;
157       
158     for ( std::size_t optr=0; optr<(G4VBiasingOperator::GetBiasingOperators()).size(); ++optr)
159     {
160       (G4VBiasingOperator::GetBiasingOperators())[optr]->EndTracking( );
161     }
162     // -- for above loop, do as in StartTracking.
163   }
164 }
165 
166 G4double G4BiasingProcessInterface::
167 PostStepGetPhysicalInteractionLength( const G4Track& track,
168                                       G4double previousStepSize,
169                                       G4ForceCondition* condition )
170 {
171   // ---------------------------------------------------------------------------------------------------
172   // -- The "biasing process master" takes care of updating the biasing operator, and for all biasing
173   // -- processes it invokes the PostStepGPIL of physical wrapped processes (anticipate stepping manager
174   // -- call ! ) to make all cross-sections updated with current step, and hence available before the
175   // -- first call to the biasing operator.
176   // ---------------------------------------------------------------------------------------------------
177   if ( fIamFirstGPIL )
178   {
179     // -- Update previous biasing operator, and assume the operator stays the same by
180     // -- default and that it is not left at the beginning of this step. These
181     // -- assumptions might be wrong if there is a volume change (in paralllel or
182     // -- mass geometries) in what case the flags will be updated.
183     fSharedData->fPreviousBiasingOperator = fSharedData->fCurrentBiasingOperator;
184     fSharedData->fIsNewOperator           = false;
185     fSharedData->fLeavingPreviousOperator = false;
186     // -- If new volume, either in mass or parallel geometries, get possible new biasing operator:
187     // -------------------------------------------------------------------------------------------
188     // -- Get biasing operator in parallel geometries:
189     G4bool firstStepInParallelVolume = false;
190     if ( fSharedData->fParallelGeometriesLimiterProcess )
191     {
192       G4VBiasingOperator* newParallelOperator( nullptr );
193       G4bool firstStep = ( track.GetCurrentStepNumber() == 1 );
194       std::size_t iParallel = 0;
195       for ( auto wasLimiting : fSharedData->fParallelGeometriesLimiterProcess->GetWasLimiting() )
196       {
197         if ( firstStep || wasLimiting )
198         {
199           firstStepInParallelVolume = true;
200           auto tmpParallelOperator = G4VBiasingOperator::
201              GetBiasingOperator((fSharedData->fParallelGeometriesLimiterProcess
202              ->GetCurrentVolumes()[iParallel])
203              ->GetLogicalVolume());
204           if ( newParallelOperator )
205           {
206             if ( tmpParallelOperator )
207             {
208               G4ExceptionDescription ed;
209               ed << " Several biasing operators are defined at the same place\n"
210                  << " in parallel geometries ! Found:\n";
211               ed << "    - `" << newParallelOperator->GetName() << "' and \n";
212               ed << "    - `" << tmpParallelOperator->GetName() << "'.\n";
213               ed << " Keeping `" << newParallelOperator->GetName()
214                  << "'. Behavior not guaranteed ! Please consider having only one operator at a place."
215                  << G4endl;
216               G4Exception(" G4BiasingProcessInterface::PostStepGetPhysicalInteractionLength(...)",
217                           "BIAS.GEN.30", JustWarning, ed);
218             }
219           }
220           else newParallelOperator = tmpParallelOperator;
221         }
222         ++iParallel;
223       }
224       fSharedData->fParallelGeometryOperator = newParallelOperator;
225     } // -- end of " if ( fSharedData->fParallelGeometriesLimiterProcess )"
226 
227     // -- Get biasing operator in mass geometry:
228     // -- [ยงยง Note : bug with this first step ? Does not work if previous step was concurrently limited with geometry. Might make use of safety at last point ?]
229     G4bool  firstStepInVolume = ( (track.GetStep()->GetPreStepPoint()->GetStepStatus() == fGeomBoundary)
230                                || (track.GetCurrentStepNumber() == 1) );
231     //      fSharedData->fIsNewOperator           = false;
232     //      fSharedData->fLeavingPreviousOperator = false;
233     if ( firstStepInVolume )
234     {
235       G4VBiasingOperator* newOperator = G4VBiasingOperator::
236         GetBiasingOperator( track.GetVolume()->GetLogicalVolume() );
237       fSharedData->fMassGeometryOperator = newOperator;
238       if ( ( newOperator != nullptr ) && ( fSharedData->fParallelGeometryOperator != nullptr ) )
239       {
240         G4ExceptionDescription ed;
241         ed << " Biasing operators are defined at the same place in mass and parallel geometries ! Found:\n";
242         ed << "    - `" << fSharedData->fParallelGeometryOperator->GetName() << "' in parallel geometry and \n";
243         ed << "    - `" << newOperator->GetName() << "' in mass geometry.\n";
244         ed << " Keeping `" << fSharedData->fParallelGeometryOperator->GetName() << "'. Behavior not guaranteed ! Please consider having only one operator at a place. " << G4endl;
245         G4Exception(" G4BiasingProcessInterface::PostStepGetPhysicalInteractionLength(...)",
246                     "BIAS.GEN.31", JustWarning, ed);
247       }
248     }
249 
250     // -- conclude the operator selection, giving priority to parallel geometry (as told in exception message BIAS.GEN.30):
251     if ( firstStepInVolume || firstStepInParallelVolume )
252     {
253       G4VBiasingOperator* newOperator = fSharedData->fParallelGeometryOperator;
254       if ( newOperator == nullptr )
255         newOperator = fSharedData->fMassGeometryOperator;
256     
257       fSharedData->fCurrentBiasingOperator = newOperator ;
258 
259       if ( newOperator != fSharedData->fPreviousBiasingOperator )
260       {
261         fSharedData->fLeavingPreviousOperator = ( fSharedData->fPreviousBiasingOperator != nullptr ) ;
262         fSharedData->fIsNewOperator = ( newOperator != nullptr );
263       }
264     }
265 
266     // -- calls to wrapped process PostStepGPIL's:
267     // -------------------------------------------
268     // -- Each physics wrapper process has its
269     // --   fWrappedProcessPostStepGPIL      ,
270     // --   fWrappedProcessForceCondition    ,
271     // --   fWrappedProcessInteractionLength
272     // -- updated.
273     if ( fSharedData->fCurrentBiasingOperator != nullptr )
274     {
275       for (std::size_t i=0; i<(fSharedData->fPhysicsBiasingProcessInterfaces).size(); ++i)
276       {
277         (fSharedData->fPhysicsBiasingProcessInterfaces)[i]->InvokeWrappedProcessPostStepGPIL( track, previousStepSize, condition );
278       }
279     }
280   } // -- end of "if ( fIamFirstGPIL )"
281 
282   // -- Remember previous operator and proposed operations, if any, and reset:
283   // -------------------------------------------------------------------------
284   // -- remember only in case some biasing might be called
285   if ( ( fSharedData->fPreviousBiasingOperator != nullptr ) ||
286        ( fSharedData->fCurrentBiasingOperator  != nullptr )    )
287   {
288     fPreviousOccurenceBiasingOperation  = fOccurenceBiasingOperation;
289     fPreviousFinalStateBiasingOperation = fFinalStateBiasingOperation;
290     fPreviousNonPhysicsBiasingOperation = fNonPhysicsBiasingOperation;
291     fPreviousBiasingInteractionLaw      = fBiasingInteractionLaw;
292     // -- reset:
293     fOccurenceBiasingOperation          = nullptr;
294     fFinalStateBiasingOperation         = nullptr;
295     fNonPhysicsBiasingOperation         = nullptr;
296     fBiasingInteractionLaw              = nullptr;
297     // -- Physics PostStep and AlongStep GPIL
298     // fWrappedProcessPostStepGPIL      : updated by InvokeWrappedProcessPostStepGPIL(...) above
299     fBiasingPostStepGPIL                = DBL_MAX;
300     // fWrappedProcessInteractionLength : updated by InvokeWrappedProcessPostStepGPIL(...) above; inverse of analog cross-section.
301     // fWrappedProcessForceCondition    : updated by InvokeWrappedProcessPostStepGPIL(...) above
302     fBiasingForceCondition              = NotForced;
303     fWrappedProcessAlongStepGPIL        = DBL_MAX;
304     fBiasingAlongStepGPIL               = DBL_MAX;
305     fWrappedProcessGPILSelection        = NotCandidateForSelection;
306     fBiasingGPILSelection               = NotCandidateForSelection;
307     // -- for helper:
308     fPreviousStepSize                   = previousStepSize;
309   }
310 
311   // -- previous step size value; it is switched to zero if resetting a wrapped process:
312   // -- (same trick used than in InvokedWrappedProcessPostStepGPIL )
313   G4double usedPreviousStepSize = previousStepSize;
314 
315   // ----------------------------------------------
316   // -- If leaving a biasing operator, let it know:
317   // ----------------------------------------------
318   if ( fSharedData->fLeavingPreviousOperator )
319   {
320     (fSharedData->fPreviousBiasingOperator)->ExitingBiasing( &track, this ); 
321     // -- if no further biasing operator, reset process behavior to standard tracking:
322     if ( fSharedData->fCurrentBiasingOperator == nullptr )
323     {
324       ResetForUnbiasedTracking();
325       if ( fIsPhysicsBasedBiasing )
326       {
327         // -- if the physics process has been under occurrence biasing, reset it:
328         if ( fResetWrappedProcessInteractionLength )
329         {
330           fResetWrappedProcessInteractionLength = false;
331           fWrappedProcess->ResetNumberOfInteractionLengthLeft();
332           // -- We set "previous step size" as 0.0, to let the process believe this is first step:
333           usedPreviousStepSize = 0.0;
334         }
335       }
336     }
337   }
338 
339   // --------------------------------------------------------------
340   // -- no operator : analog tracking if physics-based, or nothing:
341   // --------------------------------------------------------------
342   if ( fSharedData->fCurrentBiasingOperator == nullptr )
343   {
344     // -- take note of the "usedPreviousStepSize" value:
345     if ( fIsPhysicsBasedBiasing )
346     {
347       return fWrappedProcess->PostStepGetPhysicalInteractionLength(track, usedPreviousStepSize, condition);
348     }
349     else
350     {
351       *condition = NotForced;
352       return DBL_MAX;
353     }
354   }
355 
356   // --------------------------------------------------
357   // -- A biasing operator exists. Proceed with
358   // -- treating non-physics and physics biasing cases:
359   //---------------------------------------------------
360   
361   // -- non-physics-based biasing case:
362   // ----------------------------------
363   if ( !fIsPhysicsBasedBiasing )
364   {  
365     fNonPhysicsBiasingOperation = (fSharedData->fCurrentBiasingOperator)->GetProposedNonPhysicsBiasingOperation( &track, this );
366     if ( fNonPhysicsBiasingOperation == nullptr )
367     {
368       *condition = NotForced;
369       return DBL_MAX;
370     }
371     return fNonPhysicsBiasingOperation->DistanceToApplyOperation(&track, previousStepSize, condition);
372   }
373 
374   // -- Physics based biasing case:
375   // ------------------------------
376   // -- Ask for possible GPIL biasing operation:
377   fOccurenceBiasingOperation = (fSharedData->fCurrentBiasingOperator)->GetProposedOccurenceBiasingOperation( &track, this );
378 
379   // -- no operation for occurrence biasing, analog GPIL returns the wrapped process GPIL and condition values
380   if ( fOccurenceBiasingOperation == nullptr )
381   {
382     *condition = fWrappedProcessForceCondition;
383     return fWrappedProcessPostStepGPIL;
384   }
385 
386   // -- A valid GPIL biasing operation has been proposed:
387   // -- 0) remember wrapped process will need to be reset on biasing exit, if particle survives:
388   fResetWrappedProcessInteractionLength = true;
389   // -- 1) update process interaction length for reference analog interaction law ( fWrappedProcessInteractionLength updated/collected above):
390   fPhysicalInteractionLaw->SetPhysicalCrossSection( 1.0 / fWrappedProcessInteractionLength );
391   // -- 2) Collect biasing interaction law:
392   // --    The interaction law pointer is collected as a const pointer to the interaction law object.
393   // --    This interaction law will be kept under control of the biasing operation, which is the only
394   // --    entity that will change the state of the biasing interaction law.
395   // --    The force condition for biasing is asked at the same time, passing the analog one as default:
396   fBiasingForceCondition = fWrappedProcessForceCondition;
397   fBiasingInteractionLaw = fOccurenceBiasingOperation->ProvideOccurenceBiasingInteractionLaw( this, fBiasingForceCondition );
398   // -- 3) Ask operation to sample the biasing interaction law:
399   fBiasingPostStepGPIL = fBiasingInteractionLaw->GetSampledInteractionLength();
400 
401   // -- finish
402   *condition = fBiasingForceCondition;
403   return fBiasingPostStepGPIL;
404 }
405 
406 G4VParticleChange* G4BiasingProcessInterface::PostStepDoIt(const G4Track& track,
407                                                            const G4Step& step)
408 {
409   // ---------------------------------------
410   // -- case outside of volume with biasing:
411   // ---------------------------------------
412   if ( fSharedData->fCurrentBiasingOperator == nullptr )
413     return fWrappedProcess->PostStepDoIt(track, step);
414   
415   // ----------------------------
416   // -- non-physics biasing case:
417   // ----------------------------
418   if ( !fIsPhysicsBasedBiasing )
419   {
420     G4VParticleChange* particleChange = fNonPhysicsBiasingOperation->GenerateBiasingFinalState( &track, &step );
421     (fSharedData->fCurrentBiasingOperator)->ReportOperationApplied( this, BAC_NonPhysics, fNonPhysicsBiasingOperation, particleChange );
422     return particleChange;
423   }
424 
425   // -- physics biasing case:
426   // ------------------------
427   // -- It proceeds with the following logic:
428   // -- 1) Obtain the final state
429   // --    This final state may be analog or biased.
430   // --    The biased final state is obtained through a biasing operator
431   // --    returned by the operator.
432   // -- 2) The biased final state may be asked to be "force as it is"
433   // --    in what case the particle change is returned as is to the
434   // --    stepping.
435   // --    In all other cases (analog final state or biased final but
436   // --    not forced) the final state weight may be modified by the
437   // --    occurrence biasing, if such an occurrence biasing is at play.
438   
439   // -- Get final state, biased or analog:
440   G4VParticleChange* finalStateParticleChange;
441   G4BiasingAppliedCase BAC;
442   fFinalStateBiasingOperation = (fSharedData->fCurrentBiasingOperator)->GetProposedFinalStateBiasingOperation( &track, this );
443   // -- Flag below is to force the biased generated particle change to be returned "as is" to the stepping, disregarding there
444   // -- was or not a occurrence biasing that would apply. Weight relevance under full responsibility of the biasing operation.
445   G4bool forceBiasedFinalState = false;
446   if ( fFinalStateBiasingOperation != nullptr )
447   {
448     finalStateParticleChange = fFinalStateBiasingOperation->ApplyFinalStateBiasing( this, &track, &step, forceBiasedFinalState );
449     BAC = BAC_FinalState;
450   }
451   else
452   {
453     finalStateParticleChange = fWrappedProcess->PostStepDoIt(track, step);
454     BAC =  BAC_None ;
455   }
456   
457   // -- if no occurrence biasing operation, we're done:
458   if ( fOccurenceBiasingOperation == nullptr )
459   {
460     (fSharedData->fCurrentBiasingOperator)->ReportOperationApplied( this, BAC, fFinalStateBiasingOperation, finalStateParticleChange );
461     return finalStateParticleChange;
462   }
463   
464   // -- if biased final state has been asked to be forced, we're done:
465   if ( forceBiasedFinalState )
466   {
467     (fSharedData->fCurrentBiasingOperator)->ReportOperationApplied( this, BAC, fFinalStateBiasingOperation, finalStateParticleChange );
468     return finalStateParticleChange;
469   }
470 
471   // -- If occurrence biasing, applies the occurrence biasing weight correction on top of final state (biased or not):
472   G4double weightForInteraction = 1.0;
473   if ( !fBiasingInteractionLaw->IsSingular() )
474   {
475     weightForInteraction = fPhysicalInteractionLaw->ComputeEffectiveCrossSectionAt(step.GetStepLength())
476                          / fBiasingInteractionLaw ->ComputeEffectiveCrossSectionAt(step.GetStepLength());
477   }
478   else
479   {
480     // -- at this point effective XS can only be infinite, if not, there is a logic problem
481     if ( !fBiasingInteractionLaw->IsEffectiveCrossSectionInfinite() )
482     {
483       G4ExceptionDescription ed;
484       ed << "Internal inconsistency in cross-section handling. Please report !" << G4endl;
485       G4Exception(" G4BiasingProcessInterface::PostStepDoIt(...)",
486                   "BIAS.GEN.02", JustWarning, ed);
487       // -- if XS is infinite, weight is zero (and will stay zero), but we'll do differently.
488       // -- Should foresee in addition something to remember that in case of singular
489       // -- distribution, weight can only be partly calculated
490     }
491   }
492   
493   if ( weightForInteraction <= 0. )
494   {
495     G4ExceptionDescription ed;
496     ed << " Negative interaction weight : w_I = "
497        <<  weightForInteraction << " XS_I(phys) = "
498        << fBiasingInteractionLaw ->ComputeEffectiveCrossSectionAt(step.GetStepLength())
499        <<" XS_I(bias) = "
500        << fPhysicalInteractionLaw->ComputeEffectiveCrossSectionAt(step.GetStepLength())
501        << " step length = " << step.GetStepLength()
502        << " Interaction law = `" << fBiasingInteractionLaw << "'"
503        << G4endl;
504     G4Exception(" G4BiasingProcessInterface::PostStepDoIt(...)",
505                 "BIAS.GEN.03", JustWarning, ed);
506   }
507   
508   (fSharedData->fCurrentBiasingOperator)
509      ->ReportOperationApplied( this, BAC, fOccurenceBiasingOperation,
510                                weightForInteraction,
511                                fFinalStateBiasingOperation,
512                                finalStateParticleChange );
513 
514   fOccurenceBiasingParticleChange->SetOccurenceWeightForInteraction( weightForInteraction );
515   fOccurenceBiasingParticleChange->SetSecondaryWeightByProcess( true );
516   fOccurenceBiasingParticleChange->SetWrappedParticleChange( finalStateParticleChange );
517   fOccurenceBiasingParticleChange->ProposeTrackStatus( finalStateParticleChange->GetTrackStatus() );
518   fOccurenceBiasingParticleChange->StealSecondaries(); // -- this also makes weightForInteraction applied to secondaries stolen
519 
520   // -- finish:
521   return fOccurenceBiasingParticleChange;
522 }
523 
524 // -- AlongStep methods:
525 G4double G4BiasingProcessInterface::
526 AlongStepGetPhysicalInteractionLength(const G4Track& track,
527                                             G4double previousStepSize,
528                                             G4double currentMinimumStep,
529                                             G4double& proposedSafety, 
530                                             G4GPILSelection* selection)
531 {
532   // -- for helper methods:
533   fCurrentMinimumStep = currentMinimumStep;
534   fProposedSafety = proposedSafety;
535 
536   // -- initialization default case:
537   fWrappedProcessAlongStepGPIL = DBL_MAX;
538   *selection                   = NotCandidateForSelection;
539   // ---------------------------------------
540   // -- case outside of volume with biasing:
541   // ---------------------------------------
542   if ( fSharedData->fCurrentBiasingOperator == nullptr )
543   {
544     if ( fWrappedProcessIsAlong )
545       fWrappedProcessAlongStepGPIL = fWrappedProcess
546         ->AlongStepGetPhysicalInteractionLength(track, previousStepSize,
547                                                 currentMinimumStep,
548                                                 proposedSafety, selection);
549     return fWrappedProcessAlongStepGPIL;
550   }
551   
552   // --------------------------------------------------------------------
553   // -- non-physics based biasing: no along operation expected (for now):
554   // --------------------------------------------------------------------
555   if ( !fIsPhysicsBasedBiasing ) return fWrappedProcessAlongStepGPIL;
556   
557   // ----------------------
558   // -- physics-based case:
559   // ----------------------
560   if ( fOccurenceBiasingOperation == nullptr )
561   {
562     if ( fWrappedProcessIsAlong )
563       fWrappedProcessAlongStepGPIL = fWrappedProcess
564         ->AlongStepGetPhysicalInteractionLength(track, previousStepSize,
565                                                 currentMinimumStep,
566                                                 proposedSafety, selection);
567     return fWrappedProcessAlongStepGPIL;
568   }
569 
570   // -----------------------------------------------------------
571   // -- From here we have an valid occurrence biasing operation:
572   // -----------------------------------------------------------
573   // -- Give operation opportunity to shorten step proposed by physics process:
574   fBiasingAlongStepGPIL = fOccurenceBiasingOperation->ProposeAlongStepLimit( this );
575   G4double minimumStep  = fBiasingAlongStepGPIL < currentMinimumStep
576                         ? fBiasingAlongStepGPIL : currentMinimumStep;
577   // -- wrapped process is called with minimum step ( <= currentMinimumStep passed ) : an along process can not
578   // -- have its operation stretched over what it expects:
579   if ( fWrappedProcessIsAlong )
580   {
581     fWrappedProcessAlongStepGPIL = fWrappedProcess
582       ->AlongStepGetPhysicalInteractionLength(track, previousStepSize,
583                                               minimumStep,
584                                               proposedSafety, selection);
585     fWrappedProcessGPILSelection = *selection;
586     fBiasingGPILSelection = fOccurenceBiasingOperation
587       ->ProposeGPILSelection( fWrappedProcessGPILSelection );
588   }
589   else
590   {
591     fBiasingGPILSelection = fOccurenceBiasingOperation
592       ->ProposeGPILSelection( NotCandidateForSelection );
593     fWrappedProcessAlongStepGPIL = fBiasingAlongStepGPIL;
594   }
595   
596   *selection = fBiasingGPILSelection;
597 
598   return fWrappedProcessAlongStepGPIL;
599 }
600 
601 G4VParticleChange*
602 G4BiasingProcessInterface::AlongStepDoIt(const G4Track& track,
603                                          const G4Step& step)
604 {
605   // ---------------------------------------
606   // -- case outside of volume with biasing:
607   // ---------------------------------------
608   if ( fSharedData->fCurrentBiasingOperator == nullptr )
609   {
610     if ( fWrappedProcessIsAlong )
611     {
612       return fWrappedProcess->AlongStepDoIt(track, step);
613     }
614     else
615     {
616       fDummyParticleChange->Initialize( track );
617       return fDummyParticleChange;
618     }
619   }
620   
621   // -----------------------------------
622   // -- case inside volume with biasing:
623   // -----------------------------------
624   if ( fWrappedProcessIsAlong )
625   {
626     fOccurenceBiasingParticleChange
627       ->SetWrappedParticleChange(fWrappedProcess->AlongStepDoIt(track, step));
628   }
629   else  
630   {
631     fOccurenceBiasingParticleChange->SetWrappedParticleChange ( nullptr );
632     fOccurenceBiasingParticleChange->ProposeTrackStatus( track.GetTrackStatus() );
633   }
634   G4double weightForNonInteraction (1.0);
635   if ( fBiasingInteractionLaw != nullptr ) 
636   {
637     weightForNonInteraction =
638       fPhysicalInteractionLaw->ComputeNonInteractionProbabilityAt(step.GetStepLength()) /
639       fBiasingInteractionLaw ->ComputeNonInteractionProbabilityAt(step.GetStepLength());
640       
641     fOccurenceBiasingOperation->AlongMoveBy( this, &step, weightForNonInteraction );
642 
643     if ( weightForNonInteraction <= 0. )
644     {
645       G4ExceptionDescription ed;
646       ed << " Negative non interaction weight : w_NI = " << weightForNonInteraction <<
647             " p_NI(phys) = " <<  fPhysicalInteractionLaw->ComputeNonInteractionProbabilityAt(step.GetStepLength()) <<
648             " p_NI(bias) = " <<  fBiasingInteractionLaw ->ComputeNonInteractionProbabilityAt(step.GetStepLength()) <<
649             " step length = "  <<  step.GetStepLength() <<
650             " biasing interaction law = `" << fBiasingInteractionLaw->GetName() << "'" << G4endl;
651       G4Exception(" G4BiasingProcessInterface::AlongStepDoIt(...)",
652                   "BIAS.GEN.04", JustWarning, ed);
653     }
654   }
655   
656   fOccurenceBiasingParticleChange
657     ->SetOccurenceWeightForNonInteraction( weightForNonInteraction );
658   
659   return fOccurenceBiasingParticleChange;
660 }
661 
662 // -- AtRest methods
663 G4double G4BiasingProcessInterface::
664 AtRestGetPhysicalInteractionLength(const G4Track& track,
665                                    G4ForceCondition* condition)
666 {
667   return fWrappedProcess->AtRestGetPhysicalInteractionLength(track, condition);
668 }
669 
670 G4VParticleChange* G4BiasingProcessInterface::AtRestDoIt(const G4Track& track,
671                                                          const G4Step& step)
672 {
673   return fWrappedProcess->AtRestDoIt(track, step);
674 }
675 
676 G4bool G4BiasingProcessInterface::IsApplicable(const G4ParticleDefinition& pd)
677 {
678   if ( fWrappedProcess != nullptr )
679     return fWrappedProcess->IsApplicable(pd);
680   else
681     return true;
682 }
683 
684 void  G4BiasingProcessInterface::SetMasterProcess(G4VProcess* masterP)
685 {
686   // -- Master for this process:
687   G4VProcess::SetMasterProcess(masterP);
688   // -- Master for wrapped process:
689   if ( fWrappedProcess != nullptr )
690   {
691     const G4BiasingProcessInterface* thisWrapperMaster
692       = (const G4BiasingProcessInterface *)GetMasterProcess();
693     // -- paranoia check: (?)
694     G4VProcess* wrappedMaster = nullptr;
695     wrappedMaster = thisWrapperMaster->GetWrappedProcess();
696     fWrappedProcess->SetMasterProcess( wrappedMaster );
697   }
698 }
699 
700 void G4BiasingProcessInterface::
701 BuildPhysicsTable(const G4ParticleDefinition& pd)
702 {
703   // -- Sequential mode : called second (after PreparePhysicsTable(..))
704   // -- MT mode         : called second (after PreparePhysicsTable(..)) by master thread.
705   // --                   Corresponding process instance not used then by tracking.
706   // -- PreparePhysicsTable(...) has been called first for all processes,
707   // -- so the first/last flags and G4BiasingProcessInterface vector of processes have
708   // -- been properly setup, fIamFirstGPIL is valid.
709   if ( fWrappedProcess != nullptr )
710   {
711     fWrappedProcess->BuildPhysicsTable(pd);
712   }
713 
714   if ( fIamFirstGPIL )
715   {
716     // -- Re-order vector of processes to match that of the GPIL
717     // -- (made for fIamFirstGPIL, but important is to have it made once):
718     ReorderBiasingVectorAsGPIL();
719     // -- Let operators to configure themselves for the master thread or for sequential mode.
720     // -- Intended here is in particular the registration to physics model catalog.
721     // -- The fDoCommonConfigure is to ensure that this Configure is made by only one process (othewise each first process makes the call):
722     if ( fDoCommonConfigure.Get() )
723     {
724       for ( std::size_t optr=0; optr<(G4VBiasingOperator::GetBiasingOperators()).size(); ++optr)
725       {
726         (G4VBiasingOperator::GetBiasingOperators())[optr]->Configure( );
727       }
728       fDoCommonConfigure.Put(false);
729     }
730   }
731 }
732 
733 void G4BiasingProcessInterface::
734 PreparePhysicsTable(const G4ParticleDefinition& pd)
735 {
736   // -- Sequential mode : called first (before BuildPhysicsTable(..))
737   // -- MT mode         : called first (before BuildPhysicsTable(..)) by master thread.
738   // --                   Corresponding process instance not used then by tracking.
739   // -- Let process finding its first/last position in the process manager:
740   SetUpFirstLastFlags();
741   if ( fWrappedProcess != nullptr )
742   {
743     fWrappedProcess->PreparePhysicsTable(pd);
744   }
745 }
746 
747 G4bool  G4BiasingProcessInterface::
748 StorePhysicsTable(const G4ParticleDefinition* pd, const G4String& s, G4bool f)
749 {
750   if ( fWrappedProcess != nullptr )
751     return fWrappedProcess->StorePhysicsTable(pd, s, f);
752   else
753     return false;
754 }
755 
756 G4bool G4BiasingProcessInterface::
757 RetrievePhysicsTable(const G4ParticleDefinition* pd, const G4String& s, G4bool f)
758 {
759   if ( fWrappedProcess != nullptr )
760     return fWrappedProcess->RetrievePhysicsTable(pd, s, f);
761   else
762     return false;
763 }
764 
765 void G4BiasingProcessInterface::SetProcessManager(const G4ProcessManager* mgr)
766 { 
767   if ( fWrappedProcess != nullptr )
768     fWrappedProcess->SetProcessManager(mgr);
769   else
770     G4VProcess::SetProcessManager(mgr);
771 
772   // -- initialize fSharedData pointer:
773   if (G4BiasingProcessSharedData::fSharedDataMap.Find(mgr)
774    == G4BiasingProcessSharedData::fSharedDataMap.End() )
775   {
776     fSharedData = new G4BiasingProcessSharedData( mgr );
777     G4BiasingProcessSharedData::fSharedDataMap[mgr] = fSharedData;
778   }
779   else
780   {
781     fSharedData = G4BiasingProcessSharedData::fSharedDataMap[mgr] ;
782   }
783   // -- augment list of co-operating processes:
784   fSharedData->fBiasingProcessInterfaces.push_back( this );
785   fSharedData->fPublicBiasingProcessInterfaces.push_back( this );
786   if ( fIsPhysicsBasedBiasing ) 
787   {
788     fSharedData->fPhysicsBiasingProcessInterfaces.push_back( this );
789     fSharedData-> fPublicPhysicsBiasingProcessInterfaces.push_back( this );
790   }
791   else
792   {
793     fSharedData->fNonPhysicsBiasingProcessInterfaces.push_back( this );
794     fSharedData->fPublicNonPhysicsBiasingProcessInterfaces.push_back( this );
795   }
796   // -- remember process manager:
797   fProcessManager = mgr;
798 }
799 
800 const G4ProcessManager* G4BiasingProcessInterface::GetProcessManager()
801 {
802   if ( fWrappedProcess != nullptr )
803     return fWrappedProcess->GetProcessManager();
804   else
805     return G4VProcess::GetProcessManager();
806 }
807 
808 void G4BiasingProcessInterface::
809 BuildWorkerPhysicsTable(const G4ParticleDefinition& pd)
810 {
811   // -- Sequential mode : not called
812   // -- MT mode         : called after PrepareWorkerPhysicsTable(..)
813   // -- PrepareWorkerPhysicsTable(...) has been called first for all processes,
814   // -- so the first/last flags and G4BiasingProcessInterface vector of processes have
815   // -- been properly setup, fIamFirstGPIL is valid.
816   if ( fWrappedProcess != nullptr )
817   {
818     fWrappedProcess->BuildWorkerPhysicsTable(pd);
819   }
820 
821   if ( fIamFirstGPIL )
822   {
823     // -- Re-order vector of processes to match that of the GPIL
824     // -- (made for fIamFirstGPIL, but important is to have it made once):
825     ReorderBiasingVectorAsGPIL();
826     // -- Let operators to configure themselves for the worker thread, if needed.
827     // -- Registration to physics model catalog **IS NOT** to be made here, but in Configure().
828     // -- The fDoCommonConfigure is to ensure that this Configure is made by only one process (othewise each first process makes the call):
829     if ( fDoCommonConfigure.Get() )
830     {
831       for ( std::size_t optr=0 ; optr<(G4VBiasingOperator::GetBiasingOperators()).size(); ++optr)
832       {
833         (G4VBiasingOperator::GetBiasingOperators())[optr]->ConfigureForWorker( );
834       }
835       fDoCommonConfigure.Put(false);
836     }
837   }
838 }
839 
840 void G4BiasingProcessInterface::
841 PrepareWorkerPhysicsTable(const G4ParticleDefinition& pd)
842 {
843   // -- Sequential mode : not called
844   // -- MT mode         : called first, before BuildWorkerPhysicsTable(..)
845   // -- Let process finding its first/last position in the process manager:
846   SetUpFirstLastFlags();
847 
848   if ( fWrappedProcess != nullptr )
849   {
850     fWrappedProcess->PrepareWorkerPhysicsTable(pd);
851   }
852 }
853 
854 void G4BiasingProcessInterface::ResetNumberOfInteractionLengthLeft()
855 {
856   if ( fWrappedProcess != nullptr )
857     fWrappedProcess->ResetNumberOfInteractionLengthLeft();
858 }
859 
860 G4bool G4BiasingProcessInterface::
861 GetIsFirstPostStepGPILInterface( G4bool physOnly ) const
862 {
863   G4int iPhys = ( physOnly ) ? 1 : 0;
864   return fFirstLastFlags[IdxFirstLast( 1, 1, iPhys)];
865 }
866 
867 G4bool  G4BiasingProcessInterface::
868 GetIsLastPostStepGPILInterface( G4bool physOnly ) const
869 {
870   G4int iPhys = ( physOnly ) ? 1 : 0;
871   return fFirstLastFlags[IdxFirstLast( 0, 1, iPhys)];
872 }
873 
874 G4bool G4BiasingProcessInterface::
875 GetIsFirstPostStepDoItInterface( G4bool physOnly ) const
876 {
877   G4int iPhys = ( physOnly ) ? 1 : 0;
878   return fFirstLastFlags[IdxFirstLast( 1, 0, iPhys)];
879 }
880 
881 G4bool  G4BiasingProcessInterface::
882 GetIsLastPostStepDoItInterface( G4bool physOnly ) const
883 {
884   G4int iPhys = ( physOnly ) ? 1 : 0;
885   return fFirstLastFlags[IdxFirstLast( 0, 0, iPhys)];
886 }
887 
888 G4bool G4BiasingProcessInterface::
889 IsFirstPostStepGPILInterface(G4bool physOnly) const
890 {
891   G4bool isFirst = true;
892   const G4ProcessVector* pv = fProcessManager->GetPostStepProcessVector(typeGPIL);
893   G4int thisIdx(-1);
894   for ( auto i = 0; i < (G4int)pv->size(); ++i )
895   {
896     if ( (*pv)(i) == this ) { thisIdx = i; break; }
897   }
898   if ( thisIdx < 0 ) return false; // -- to ignore pure along processes
899   for ( std::size_t i=0; i<(fSharedData->fBiasingProcessInterfaces).size(); ++i )
900   {
901     if ( (fSharedData->fBiasingProcessInterfaces)[i]->fIsPhysicsBasedBiasing || !physOnly )
902     {
903       G4int thatIdx(-1);
904       for (auto j = 0; j < (G4int)pv->size(); ++j )
905       {
906         if ( (*pv)(j) == (fSharedData->fBiasingProcessInterfaces)[i] )
907         {
908           thatIdx = j; break;
909         }
910       }
911       if ( thatIdx >= 0 ) // -- to ignore pure along processes
912       {
913         if ( thisIdx >  thatIdx )
914         {
915           isFirst = false;
916           break;
917         }
918       }
919     }
920   }
921   return isFirst;
922 }
923 
924 G4bool G4BiasingProcessInterface::
925 IsLastPostStepGPILInterface(G4bool physOnly) const
926 {
927   G4bool isLast = true;
928   const G4ProcessVector* pv = fProcessManager->GetPostStepProcessVector(typeGPIL);
929   G4int thisIdx(-1);
930   for (auto i = 0; i < (G4int)pv->size(); ++i )
931   {
932     if ( (*pv)(i) == this ) { thisIdx = i; break; }
933   }
934   if ( thisIdx < 0 ) return false; // -- to ignore pure along processes
935   for (std::size_t i=0; i<(fSharedData->fBiasingProcessInterfaces).size(); ++i)
936   {
937     if ( (fSharedData->fBiasingProcessInterfaces)[i]->fIsPhysicsBasedBiasing || !physOnly )
938     {
939       G4int thatIdx(-1);
940       for (auto j = 0; j < (G4int)pv->size(); ++j )
941       {
942         if ( (*pv)(j) == (fSharedData->fBiasingProcessInterfaces)[i] )
943         {
944           thatIdx = j; break;
945         }
946       }
947       if ( thatIdx >= 0 ) // -- to ignore pure along processes
948       {
949         if ( thisIdx <  thatIdx )
950         {
951           isLast = false;
952           break;
953         }
954       }
955     }
956   }
957   return isLast;  
958 }
959 
960 G4bool G4BiasingProcessInterface::
961 IsFirstPostStepDoItInterface(G4bool physOnly) const
962 {
963   G4bool isFirst = true;
964   const G4ProcessVector* pv = fProcessManager->GetPostStepProcessVector(typeDoIt);
965   G4int thisIdx(-1);
966   for (auto i = 0; i < (G4int)pv->size(); ++i )
967   {
968     if ( (*pv)(i) == this ) { thisIdx = i; break; }
969   }
970   if ( thisIdx < 0 ) return false; // -- to ignore pure along processes
971   for (std::size_t i=0; i<(fSharedData->fBiasingProcessInterfaces).size(); ++i)
972   {
973     if ( (fSharedData->fBiasingProcessInterfaces)[i]->fIsPhysicsBasedBiasing || !physOnly )
974     {
975       G4int thatIdx(-1);
976       for (auto j = 0; j < (G4int)pv->size(); ++j )
977       {
978         if ( (*pv)(j) == (fSharedData->fBiasingProcessInterfaces)[i] )
979         {
980           thatIdx = j; break;
981         }
982       }
983       if ( thatIdx >= 0 ) // -- to ignore pure along processes
984       {
985         if ( thisIdx >  thatIdx )
986         {
987           isFirst = false;
988           break;
989         }
990       }
991     }
992   }
993   return isFirst;
994 }
995 
996 G4bool G4BiasingProcessInterface::
997 IsLastPostStepDoItInterface(G4bool physOnly) const
998 {
999   G4bool isLast = true;
1000   const G4ProcessVector* pv = fProcessManager->GetPostStepProcessVector(typeDoIt);
1001   G4int thisIdx(-1);
1002   for (auto i = 0; i < (G4int)pv->size(); ++i)
1003   {
1004     if ( (*pv)(i) == this ) { thisIdx = i; break; }
1005   }
1006   if ( thisIdx < 0 ) return false; // -- to ignore pure along processes
1007   for (std::size_t i=0; i<(fSharedData->fBiasingProcessInterfaces).size(); ++i)
1008   {
1009     if ( (fSharedData->fBiasingProcessInterfaces)[i]->fIsPhysicsBasedBiasing || !physOnly )
1010     {
1011       G4int thatIdx(-1);
1012       for (auto j = 0; j < (G4int)pv->size(); ++j)
1013       {
1014         if ( (*pv)(j) == (fSharedData->fBiasingProcessInterfaces)[i] )
1015         {
1016           thatIdx = j; break;
1017         }
1018       }
1019       if ( thatIdx >= 0 ) // -- to ignore pure along processes
1020       {
1021         if ( thisIdx <  thatIdx )
1022         {
1023           isLast = false;
1024           break;
1025         }
1026       }
1027     }
1028   }
1029   return isLast;  
1030 }
1031 
1032 void G4BiasingProcessInterface::SetUpFirstLastFlags()
1033 {
1034   for (G4int iPhys = 0; iPhys < 2; ++iPhys)
1035   {
1036     G4bool physOnly = ( iPhys == 1 );
1037     fFirstLastFlags[IdxFirstLast( 1, 1, iPhys)] = IsFirstPostStepGPILInterface(physOnly);
1038     fFirstLastFlags[IdxFirstLast( 0, 1, iPhys)] =  IsLastPostStepGPILInterface(physOnly);
1039     fFirstLastFlags[IdxFirstLast( 1, 0, iPhys)] = IsFirstPostStepDoItInterface(physOnly);
1040     fFirstLastFlags[IdxFirstLast( 0, 0, iPhys)] =  IsLastPostStepDoItInterface(physOnly);
1041   }
1042   
1043   // -- for itself, for optimization:
1044   fIamFirstGPIL =  GetIsFirstPostStepGPILInterface( false );
1045 }
1046 
1047 void G4BiasingProcessInterface::ResetForUnbiasedTracking()
1048 {
1049   fOccurenceBiasingOperation  = nullptr;
1050   fFinalStateBiasingOperation = nullptr;
1051   fNonPhysicsBiasingOperation = nullptr;
1052   fBiasingInteractionLaw      = nullptr;
1053 }
1054 
1055 void G4BiasingProcessInterface::
1056 InvokeWrappedProcessPostStepGPIL( const G4Track&  track,
1057                                   G4double previousStepSize,
1058                                   G4ForceCondition* condition )
1059 {
1060   G4double usedPreviousStepSize = previousStepSize;
1061   // -- if the physics process has been under occurrence biasing in the previous step
1062   // -- we reset it, as we don't know if it will be biased again or not in this
1063   // -- step. The pity is that PostStepGPIL and interaction length (cross-section)
1064   // -- calculations are done both in the PostStepGPIL of the process, while here we
1065   // -- are just interested in the calculation of the cross-section. This is a pity
1066   // -- as this forces to re-generated a random number for nothing.
1067   if ( fResetWrappedProcessInteractionLength )
1068   {
1069     fResetWrappedProcessInteractionLength = false;
1070     fWrappedProcess->ResetNumberOfInteractionLengthLeft();
1071     // -- We set "previous step size" as 0.0, to let the process believe this is first step:
1072     usedPreviousStepSize = 0.0;
1073   }
1074   // -- GPIL response:
1075   fWrappedProcessPostStepGPIL = fWrappedProcess->PostStepGetPhysicalInteractionLength(track, usedPreviousStepSize, condition);
1076   fWrappedProcessForceCondition = *condition;
1077   // -- and (inverse) cross-section:
1078   fWrappedProcessInteractionLength = fWrappedProcess->GetCurrentInteractionLength();
1079 }
1080 
1081 void G4BiasingProcessInterface::ReorderBiasingVectorAsGPIL()
1082 {
1083   // -- re-order vector of processes to match that of the GPIL:
1084   std::vector < G4BiasingProcessInterface* > tmpProcess ( fSharedData->fBiasingProcessInterfaces );
1085   ( fSharedData -> fBiasingProcessInterfaces                 ) . clear();
1086   ( fSharedData -> fPhysicsBiasingProcessInterfaces          ) . clear();
1087   ( fSharedData -> fNonPhysicsBiasingProcessInterfaces       ) . clear();
1088   ( fSharedData -> fPublicBiasingProcessInterfaces           ) . clear();
1089   ( fSharedData -> fPublicPhysicsBiasingProcessInterfaces    ) . clear();
1090   ( fSharedData -> fPublicNonPhysicsBiasingProcessInterfaces ) . clear();
1091   
1092   const G4ProcessVector* pv = fProcessManager->GetPostStepProcessVector(typeGPIL);
1093   for (auto i = 0; i < (G4int)pv->size(); ++i) 
1094   {
1095     for (std::size_t j = 0; j < tmpProcess.size(); ++j)
1096     {
1097       if ( (*pv)(i) == tmpProcess[j] )
1098       { 
1099         ( fSharedData->fBiasingProcessInterfaces ).push_back( tmpProcess[j] );
1100         ( fSharedData->fPublicBiasingProcessInterfaces ).push_back( tmpProcess[j] );
1101         if ( tmpProcess[j] -> fIsPhysicsBasedBiasing )
1102         {
1103           ( fSharedData->fPhysicsBiasingProcessInterfaces ).push_back( tmpProcess[j] );
1104           ( fSharedData->fPublicPhysicsBiasingProcessInterfaces ).push_back( tmpProcess[j] ); 
1105         }
1106         else
1107         {
1108           ( fSharedData -> fNonPhysicsBiasingProcessInterfaces ).push_back( tmpProcess[j] );
1109           ( fSharedData -> fPublicNonPhysicsBiasingProcessInterfaces ).push_back( tmpProcess[j] );  
1110         }
1111         break;
1112       }
1113     }
1114   }
1115 }
1116